• NOIP2014-3-15模拟赛


    Problem 1 高级打字机(type.cpp/c/pas)

    【题目描述】

    早苗入手了最新的高级打字机。最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧。

    请为这种高级打字机设计一个程序,支持如下3种操作:

    1.T x:在文章末尾打下一个小写字母x。(type操作)

    2.U x:撤销最后的x次修改操作。(Undo操作)

    (注意Query操作并不算修改操作)

    3.Q x:询问当前文章中第x个字母并输出。(Query操作)

    文章一开始可以视为空串。

    【输入格式】

    1行:一个整数n,表示操作数量。

    以下n行,每行一个命令。保证输入的命令合法。

    【输出格式】

    每行输出一个字母,表示Query操作的答案。

    【样例输入】

    7

    T a

    T b

    T c

    Q 2

    U 2

    T c

    Q 2

    【样例输出】

    b

    c

    【数据范围】

    对于40%的数据 n<=200;

    对于100%的数据 n<=100000;保证Undo操作不会撤销Undo操作。

    <高级挑战>

    对于200%的数据 n<=100000;Undo操作可以撤销Undo操作。

    <IOI挑战>

    必须使用在线算法完成该题。

    Problem 2 不等数列(num.cpp/c/pas)

    【题目描述】

    1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2012取模。

    【输入格式】

    第一行2个整数n,k。

    【输出格式】

    一个整数表示答案。

    【样例输入】

    5 2

    【样例输出】

    66

    【数据范围】

    对于30%的数据:n <= 10

    对于100%的数据:k < n <= 1000,

    Problem 3 经营与开发(exploit.cpp/c/pas)

    【题目描述】

    4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词。

    eXplore(探索)

    eXpand(拓张与发展)

    eXploit(经营与开发)

    eXterminate(征服)

    ——维基百科

    今次我们着重考虑exploit部分,并将其模型简化:

    你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球。

    星球笼统的分为2类:资源型和维修型。(p为钻头当前能力值)

    1.资源型:含矿物质量a[i],若选择开采,则得到a[i]*p的金钱,之后钻头损耗k%,即p=p*(1-0.01k)

    2.维修型:维护费用b[i],若选择维修,则支付b[i]*p的金钱,之后钻头修复c%,即p=p*(1+0.01c)

        注:维修后钻头的能力值可以超过初始值(你可以认为是翻修+升级)

    请作为舰长的你仔细抉择以最大化收入。

    【输入格式】

    第一行4个整数n,k,c,w。

    以下n行,每行2个整数type,x。

    type为1则代表其为资源型星球,x为其矿物质含量a[i];

    type为2则代表其为维修型星球,x为其维护费用b[i];

    【输出格式】

    一个实数(保留2位小数),表示最大的收入。

    【样例输入】

    5 50 50 10

    1 10

    1 20

    2 10

    2 20

    1 30

    【样例输出】

    375.00

    【数据范围】

    对于30%的数据 n<=100

    另有20%的数据 n<=1000;k=100

    对于100%的数据 n<=100000; 0<=k,c,w,a[i],b[i]<=100;保证答案不超过10^9


    T1:

    这题看起来挺简单,实际上比较麻烦

    对于50%的数据,代码很好写:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MAXN 100005
     6 using namespace std;
     7 char s[MAXN];
     8 int p;
     9 int main()
    10 {
    11     int T;
    12     scanf("%d",&T);
    13     for(int i=1;i<=T;i++){
    14         char c;
    15         scanf(" %c",&c);
    16         if('T'==c){
    17             char x;
    18             scanf(" %c",&x);
    19             s[++p]=x;
    20         }
    21         else{
    22             int x;
    23             scanf("%d",&x);
    24             if('U'==c){
    25                 p-=x;
    26             }
    27             else{
    28                 printf("%c
    ",s[x]);
    29             }
    30         }
    31     }
    32     return 0;
    33 }
    Code1

    对于50%+的数据,就有点麻烦了,我是直接暴力转移的,80分,两个点MLE

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<vector>
     6 #define MAXN 100005
     7 using namespace std;
     8 int n;
     9 char p[MAXN],X[MAXN];
    10 int b[MAXN],to[MAXN];
    11 vector<char> s[MAXN];
    12 vector<char> find(int x){
    13     if(b[x]||!x){
    14         return s[x];
    15     }
    16     s[x]=find(to[x]);
    17     if('T'==p[x])
    18         s[x].push_back(X[x]);
    19     b[x]=1;
    20     return s[x];
    21 }
    22 int main()
    23 {
    24 //    freopen("type06.in","r",stdin);
    25 //    freopen("my.out","w",stdout);
    26     scanf("%d",&n);
    27     scanf(" %c",&p[1]);
    28     scanf(" %c",&p[1]);
    29     s[1].push_back(p[1]);
    30     b[1]=1;
    31     for(int i=2;i<=n;i++){
    32         scanf(" %c",&p[i]);
    33         if('T'==p[i]){
    34             scanf(" %c",&X[i]);
    35             to[i]=i-1;
    36         }
    37         else{
    38             int x;
    39             scanf("%d",&x);
    40             if('U'==p[i]){
    41                 to[i]=i-x-1;
    42             }
    43             else{
    44                 vector<char> temp(find(i-1));
    45                 printf("%c
    ",temp[x-1]);
    46                 i--;
    47                 n--;
    48             }
    49         }
    50 //        for(int j=0;j<s[i].size();j++){
    51 //            printf("%c",s[i][j]);
    52 //        }
    53 //        printf("
    ");
    54     }
    55     return 0;
    56 }
    Code2

    正解是巧妙利用转移顺序的离线算法,把转移看成一棵树,走欧拉路使得复杂度降为O(n)

    (PS:代码是标程代码,我的不知道怎么回事不能AC,调了一下午ToT)

     1 #include<cstdio>
     2 #include<vector>
     3 #define pb push_back
     4 #define rep(i,n) for(int i=0;i<n;i++)
     5 
     6 using namespace std;
     7 
     8 const int maxn=100010;
     9 int n,q,x,v,sz,tot,fa[maxn],en[maxn],pre[maxn],g[maxn],ans[maxn];
    10 char ch,a[maxn],sk[maxn];
    11 
    12 vector <int> lk[maxn];
    13 
    14 void Ins(int u,int v)
    15 {
    16     pre[++sz]=en[u];en[u]=sz;g[sz]=v;
    17 }
    18 void Type()
    19 {
    20     scanf("%s",&ch);
    21     a[tot]=ch;
    22     tot++;
    23     fa[tot]=tot-1;
    24 
    25 }
    26 void Undo()
    27 {
    28     scanf("%d",&x);
    29     tot++;
    30     Ins(tot-x-1,tot);
    31     fa[tot]=tot-x-1;
    32 }
    33 void Query()
    34 {
    35     scanf("%d",&x);
    36     lk[tot].pb(q);
    37     ans[q++]=x;
    38 }
    39 
    40 void DFS()
    41 {
    42     tot=x=0;
    43     for(x=0;;)
    44     {
    45         if (en[x])
    46         {
    47             v=g[en[x]];
    48             en[x]=pre[en[x]];
    49             x=v;continue;
    50         }
    51         if (a[x])
    52         {
    53             sk[++tot]=a[x];
    54             a[x]=0;
    55             x++;continue;
    56         }
    57         rep(i,lk[x].size())
    58         {
    59             v=lk[x][i];
    60             ans[v]=sk[ans[v]];
    61         }
    62         if (fa[x]+1==x) tot--;
    63         if (!x) return;
    64         x=fa[x];
    65     }
    66 }
    67 int main()
    68 {
    69 //    freopen("type.in","r",stdin);
    70 //    freopen("type.out","w",stdout);
    71     scanf("%d
    ",&n);
    72     rep(i,n)
    73     {
    74         scanf("%s",&ch);
    75         switch (ch)
    76         {
    77             case 'T':Type();break;
    78             case 'U':Undo();break;
    79             case 'Q':Query();break;
    80         }
    81     }
    82     DFS();
    83     rep(i,q) printf("%c
    ",ans[i]);
    84     return 0;
    85 }
    Code3

    T2:

    这个想想看下数据范围1000,1000,肯定是dp了

    考虑把n插入n-1个数中去,分类讨论下,即可得到状态转移方程:

    f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1)

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MAXN 1005
     6 #define MOD 2012
     7 using namespace std;
     8 int f[MAXN][MAXN];
     9 int n,k;
    10 int main()
    11 {
    12     scanf("%d%d",&n,&k);
    13     for(int i=1;i<=n;i++){
    14         f[i][0]=1;
    15     }
    16     for(int i=2;i<=n;i++){
    17         for(int j=1;j<n;j++){
    18             f[i][j]=(f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1))%MOD;
    19         }
    20     }
    21     printf("%d
    ",f[n][k]);
    22     return 0;
    23 }
    Code4

    T3:

    这题我想了好久啊,还是没有什么思路,泪奔~~~~~o(>_<)o ~~

    暴力算法:

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<vector>
     6 #define MAXN 100005
     7 using namespace std;
     8 int n;
     9 double k,c,w;
    10 vector<pair<double,double> > s;
    11 int main()
    12 {
    13 //    freopen("data.in","r",stdin);
    14     scanf("%d",&n);
    15     scanf("%lf%lf%lf",&k,&c,&w);
    16     k=(1-0.01*k),c=(1+0.01*c);
    17     s.push_back(make_pair(0,w));
    18     double ans=0;
    19     for(int i=1;i<=n;i++){
    20         int type,t;
    21         scanf("%d",&type);
    22         int sz=s.size();
    23         if(1==type){
    24             scanf("%d",&t);
    25             for(int j=0;j<sz;j++){
    26                 double m=s[j].first,p=s[j].second;
    27                 m+=t*p; p*=k;
    28                 ans=max(ans,m);
    29                 s.push_back(make_pair(m,p));
    30             }
    31         }
    32         else{
    33             scanf("%d",&t);
    34             for(int j=0;j<sz;j++){
    35                 double m=s[j].first,p=s[j].second;
    36                 m-=t*p; p*=c;
    37                 ans=max(ans,m);
    38                 s.push_back(make_pair(m,p));
    39             }
    40         }
    41     }
    42     printf("%.2f",ans);
    43     return 0;
    44 }
    Code5

    得了10分QAQ

    其实似乎可以优化下的,比如钱少性能又坏,那么肯定不要了

    正解的思路妙啊~

    发现开采:得到a[i]*p的金钱 之后钻头损耗k%,即p=p*(1-0.01k)

    维修:支付b[i]*p的金钱,之后钻头修复c%,即p=p*(1+0.01c)

    如果把最优解用一个多项式表示出来的话,肯定有一个公因数p!

    那么我们就提取这个公因数,发现之后的无论咋搞,与p没关系了!

    那么我们不妨认为p=1,然后万事大吉~

    设f[i]表示开采i~n的最优解,且初始强度为1

    那么有f[i]=max(f[i+1],f[i+1]*(1-0.01k)+a[i]或者是f[i+1]*(1+0.01c)-b[i])

    ans为f[1]*w AC!

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define MAXN 100005
     6 using namespace std;
     7 int n;
     8 double f[MAXN];
     9 double k,c,w;
    10 double a[MAXN],b[MAXN];
    11 
    12 int main()
    13 {
    14     scanf("%d",&n);
    15     scanf("%lf%lf%lf",&k,&c,&w);
    16     k=(1-0.01*k),c=(1+0.01*c);
    17     for(int i=1;i<=n;i++){
    18         int t;
    19         scanf("%d",&t);
    20         scanf("%lf",&a[i]);
    21         if(t==1){
    22             b[i]=k;
    23         }
    24         else{
    25             a[i]*=-1;
    26             b[i]=c;
    27         }
    28     }
    29     for(int i=n;i>=1;i--){
    30         f[i]=max(f[i+1],f[i+1]*b[i]+a[i]);
    31     }
    32     printf("%.2f",f[1]*w);
    33     return 0;
    34 }
    Code6
  • 相关阅读:
    Winfrom判断用户输入是否为int整型方法之一!
    C#winfrom 中的MessageBox 弹出提示框
    C# WinForm窗口关闭的几种常用方法
    excel数据生成sql语句
    Redis 发布和订阅
    C# Redis消息队列例子2
    C# Redis消息队列例子
    win10屏幕亮度无法调节,已解决
    VUE 日期组件(包括年选择)
    暴力递归-逆序栈
  • 原文地址:https://www.cnblogs.com/w-h-h/p/7581946.html
Copyright © 2020-2023  润新知