NOIP2014-3-15模拟赛

时间:2022-12-17 11:17:31

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%的数据,代码很好写:

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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\n",s[x]);
29             }
30         }
31     }
32     return 0;
33 }
Code1

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

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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\n",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("\n");
54     }
55     return 0;
56 }
Code2

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

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

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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",&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\n",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)

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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\n",f[n][k]);
22     return 0;
23 }
Code4

T3:

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

暴力算法:

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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!

NOIP2014-3-15模拟赛NOIP2014-3-15模拟赛
 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