1. 程式人生 > >【題解】洛谷P4853[非酋yyf的sif之旅]B.yyf hates choukapai 單調佇列優化DP

【題解】洛谷P4853[非酋yyf的sif之旅]B.yyf hates choukapai 單調佇列優化DP

題目連結 在這裡插入圖片描述 在這裡插入圖片描述

賽後題解

#include<cstdio>
const int M=8e4+5,C=3e3+5,N=45,S=N*C+M;
int a[S],b[S],n,m,c,d,sum,hd[N],tl[N],s,q[N][S][2],f[S][N],p[S][N],pos[N],ans,Pos;
//f[i][j]前i張牌連抽j次 p[i][j]記錄f[i][j]由哪個i轉移過來 
int main()
{
	//freopen("in.txt","r",stdin);
    scanf("%d%d%d%d",&n,&m,&c,&d);s=n*c+m;
    for(int i=1;i<=s;i++)
        scanf("%d",&a[i]),sum+=a[i];
    for(int i=2;i<=c;i++)
        b[1]+=a[i];
    for(int i=2;i<=s-c+1;i++)
        b[i]=b[i-1]-a[i]+a[i+c-1];//b[i]維護a[i+1]加到a[i+c-1] 
    for(int i=1;i<=n;i++)
        hd[i]=1;
    for(int i=1;i<=s-c+1;i++)
    {
    	if(i<=c){f[i][1]=b[i];continue;}
    	for(int j=(i+c-2)/(c+d)+1;j<=(i+c-1)/c&&j<=n;j++)
    	{
    		if(hd[j-1]<=tl[j-1]&&q[j-1][hd[j-1]][1]<i-c-d)//隊頭超出範圍的出隊 
    		    hd[j-1]++;
    		if(j-1>=(i-2)/(c+d)+1&&j-1<=(i-1)/c)
    		{//能入隊的入隊 
    			while(hd[j-1]<=tl[j-1]&&q[j-1][tl[j-1]][0]>=f[i-c][j-1])
    			    tl[j-1]--;
    			q[j-1][++tl[j-1]][0]=f[i-c][j-1];//0記錄的最大值 
    			q[j-1][tl[j-1]][1]=i-c;//1記錄的位置 
			}
			f[i][j]=q[j-1][hd[j-1]][0]+b[i];
			p[i][j]=q[j-1][hd[j-1]][1];
			if(i>=s-c+1-d&&j==n&&ans<sum-f[i][j])
			    ans=sum-f[i][j],Pos=i;
		}
	}
	printf("%d\n",ans);
	for(int j=n;j;j--)
	    pos[j]=Pos,Pos=p[Pos][j];
	for(int i=1;i<=n;i++)
	    printf("%d ",pos[i]);
	puts("");
	return 0;
}

總結

當時好像是寫了個0分的DP還是啥的,心態直接炸了,T3也沒咋寫就放棄了。自己的心態還是得練練,畢竟以後寫不來的比賽題多了去了(笑) 自己動態規劃太菜,這種狀態轉移方程都毫無頭緒。狀態轉移方程出來單調佇列就顯而易見了。