1. 程式人生 > >NOIP2014-3-15模擬賽

NOIP2014-3-15模擬賽

數據 模擬 lose 開頭 exp dfs noi 發展 取模

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\n",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\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)

技術分享
 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)

技術分享
 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 ~~

暴力算法:

技術分享
 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

NOIP2014-3-15模擬賽