「NOI2013」小 Q 的修煉
第一次完整的作出一個提答,花了半個晚上+一個上午+半個下午node
整體來講太慢了url
對於此題,我認爲的難點是觀察數據並猜想性質和讀入操做spa
我隔一會就思考這個sb字符串讀起來怎麼這麼麻煩啊.net
首先能夠發現,這個全部的選擇都以後日後走,就是個topo圖code
-
task1,2,3字符串
觀察到數據有形如get
s x x+11 v 3 + c y v 4 + c y v 5 + c y v 6 + c y v 7 + c y v 8 + c y v 9 + c y v 10 + c y v 11 + c y v 12 + c y
之類的東西,並且每一個這樣的循環後面有一個這樣的東西string
i v 3 c 0 43 45 v 1 - v 3 i c 0 c 1 46 0 v 1 + v 3 v 3 - v 3 i v 4 c 0 48 50 v 1 - v 4 i c 0 c 1 51 0 v 1 + v 4 v 4 - v 4 ...
發現這個就是把正的數據加到1上,負的不變並清空it
這樣就無法貪心或者dp了io
而後咱們又發現循環長度很小,直接爆搜就好了
代碼搞丟了..
S_1 要討論走哪一個循環
S_2 直接爆搜
S_3 發現又不少組,分組爆搜
-
task4,5,6
最開始對變量2有一個正的初值
而後
s 5 8 v 2 - c 10 v 1 + c 22750 i c 0 c 1 8 0 i v 2 c 9 9 10 i c 0 c 1 14 0
循環節長這樣
每次若是選擇,會有一些跳轉之類的
發現2的初值比較小並且後面只會減
考慮dp
$dp_{i,j}$第$i$行第$2$個變量的值是$j$的時候最大的$1$
而後模擬轉移,記錄路徑就能夠了
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using std::max; const int N=6010; int n,m; char op[5],t0[10],t1[10]; int x0,x1,x2,x2; struct koito_yuu { int op,a,b,c; koito_yuu(){} koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;} }yuu[N]; struct node { int i,j,cho; node(){} node(int I,int J,int Cho){i=I,j=J,cho=Cho;} }pre[N][5010]; ll dp[N][5010]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",op); if(op[0]=='s') { tim[++k]=i; scanf("%d%d",&x1,&x2); yuu[i]=koito_yuu(1,x1,x2,0); } else if(op[0]=='v') { scanf("%d%s%s%d",&x0,t0,t1,&x1); yuu[i]=koito_yuu(2,x0,t1[0]=='+'?x1:-x1,0); } else { scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3); if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(3,x2,0,0); else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(4,x1,x2,x3); } } memset(dp,-0x3f,sizeof dp); int inf=dp[0][0]; dp[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<=5000;j++) if(dp[i-1][j]!=inf) { if(yuu[i].op==1) { int a=yuu[i].a,b=yuu[i].b; if(dp[a][j]<dp[i][j]) { pre[a][j]=node(i,j,1); dp[a][j]=dp[i][j]; } if(dp[b][j]<dp[i][j]) { pre[b][j]=node(i,j,2); dp[b][j]=dp[i][j]; } } else if(yuu[i].op==2) { int a=yuu[i].a,b=yuu[i].b; if(a==1) { if(dp[i+1][j]<dp[i][j]+b) { pre[i+1][j]=node(i,j,0); dp[i+1][j]=dp[i][j]+b; } } else { int t=max(0,j+b); if(dp[i+1][t]<dp[i][j]) { pre[i+1][t]=node(i,j,0); dp[i+1][t]=dp[i][j]; } } } else if(yuu[i].op==3) { int a=yuu[i].a; if(dp[a][j]<dp[i][j]) { pre[a][j]=node(i,j,0); dp[a][j]=dp[i][j]; } } else { int a=yuu[i].a,b=yuu[i].b,c=yuu[i].c; if(j<a) { if(dp[b][j]<dp[i][j]) { pre[b][j]=node(i,j,0); dp[b][j]=dp[i][j]; } } else { if(dp[c][j]<dp[i][j]) { pre[c][j]=node(i,j,0); dp[c][j]=dp[i][j]; } } } } int tj=0; for(int i=1;i<=5000;i++) if(dp[n+1][tj]<dp[n+1][i]) tj=i; int ti=n+1,cnt=0; while(ti) { int tx=ti,ty=tj; ti=pre[tx][ty].i,tj=pre[tx][ty].j; if(pre[tx][ty].cho) ans[++cnt]=pre[tx][ty].cho; } for(int i=cnt;i;i--) printf("%d\n",ans[i]); return 0; }
4,5,6都是同樣的
我本地跑6的時候竟然開不下空間,還壓了一會T_T
-
task7,8,9,10
這四個點就是前面的結合
最開始的時候有2控制跳轉的東西
中間就是1,2,3點的循環
差很少175行一個週期
對週期壓變量2的長度dp,每一個週期裏面爆搜
提及來簡單,寫起來仍是很麻煩的
我這個代碼要把in的最後幾行刪掉
Code:
#include <cstdio> #include <cstring> #include <algorithm> #define ll long long using std::max; using std::min; const int N=35010; int n,m; char op[5],t0[10],t1[10]; int x0,x1,x2,x3; struct koito_yuu { int op,a,b,c; koito_yuu(){} koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;} }yuu[N]; struct node { int i,j,cho; node(){} node(int I,int J,int Cho){i=I,j=J,cho=Cho;} }pre[N][1010]; ll dp[N][1010]; int Id[N],as[N][20],yuy[20][20],ct[N]; ll solve(int id,int L,int R) { int n=0; for(int i=L;i<=R;i++) { if(yuu[i].op==1) ++n,yuy[n][0]=0; if(yuu[i].op==2) yuy[n][++yuy[n][0]]=yuu[i].b; if(yuu[i].op==3) break; } ll mx=-(1ll<<52); ct[id]=n; for(int s=0;s<1<<n;s++) { ll sum[20]={}; for(int i=1;i<=n;i++) if(s>>i-1&1) { for(int j=1;j<=10;j++) sum[j]+=yuy[i][j]; } ll su=0; for(int i=1;i<=10;i++) su+=sum[i]>0?sum[i]:-sum[i]; if(mx<su) { mx=su; for(int i=1;i<=n;i++) if(s>>i-1&1) as[id][i]=1; else as[id][i]=2; } } return mx; } int endro[N],k,ans[N]; int main() { freopen("train8.in","r",stdin); freopen("train8.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",op); if(op[0]=='s') { scanf("%d%d",&x1,&x2); x2=min(x2,n+1); yuu[i]=koito_yuu(1,x1,x2,0); } else if(op[0]=='v') { scanf("%d%s%s%d",&x0,t0,t1,&x1); if(t1[0]=='c') { yuu[i]=koito_yuu(2,x0,t0[0]=='+'?x1:-x1,0); } else { yuu[i]=koito_yuu(3,x0,0,x1); if(x0==12) endro[++k]=i; } } else { scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3); x2=min(x2,n+1),x3=min(x3,n+1); if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(4,x2,0,0); else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(5,x1,x2,x3); } } memset(dp,-0x3f,sizeof dp); dp[1][0]=0; for(int i=1;i<=k;i++) { int tp; for(int j=endro[i-1]+1;;j++) if(yuu[j].op==1&&yuu[j].b-yuu[j].a==11) { tp=j-1; break; } ll ad=solve(i,tp+1,endro[i]); for(int l=endro[i-1]+1;l<=tp;l++) for(int j=0;j<=1000;j++) { if(yuu[l].op==1) { int a=yuu[l].a,b=yuu[l].b; if(dp[a][j]<dp[l][j]) { dp[a][j]=dp[l][j]; pre[a][j]=node(l,j,1); } if(dp[b][j]<dp[l][j]) { dp[b][j]=dp[l][j]; pre[b][j]=node(l,j,2); } } else if(yuu[l].op==2) { int b=yuu[l].b; int t=max(0,j+b); if(dp[l+1][t]<dp[l][j]) { dp[l+1][t]=dp[l][j]; pre[l+1][t]=node(l,j,0); } } else if(yuu[l].op==4) { int a=yuu[l].a; if(dp[a][j]<dp[l][j]) { dp[a][j]=dp[l][j]; pre[a][j]=node(l,j,0); } } else { int a=yuu[l].a,b=yuu[l].b,c=yuu[l].c; if(j<a) { if(dp[b][j]<dp[l][j]) { dp[b][j]=dp[l][j]; pre[b][j]=node(l,j,0); } } else { if(dp[c][j]<dp[l][j]) { dp[c][j]=dp[l][j]; pre[c][j]=node(l,j,0); } } } } int s=tp+1,t=endro[i]+1; Id[s]=i; for(int j=0;j<=1000;j++) if(dp[t][j]<dp[s][j]+ad) { dp[t][j]=dp[s][j]+ad; pre[t][j]=node(s,j,3); } } //9.22925584 //10.20218188 int tj=0; for(int i=1;i<=1000;i++) if(dp[n+1][tj]<dp[n+1][i]) tj=i; int ti=n+1,cnt=0; while(ti) { int tx=ti,ty=tj; ti=pre[tx][ty].i,tj=pre[tx][ty].j; if(pre[tx][ty].cho) { if(pre[tx][ty].cho==3) { int id=Id[ti]; for(int i=ct[id];i;i--) ans[++cnt]=as[id][i]; } else ans[++cnt]=pre[tx][ty].cho; } } for(int i=cnt;i;i--) printf("%d\n",ans[i]); return 0; }
2019.4.12