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行,每行一個命令。保證輸入的命令合法。
【輸出格式】
每行輸出一個字母,表示
【樣例輸入】
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模擬賽