「NOI2013」小 Q 的修煉 解題報告

「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

相關文章
相關標籤/搜索