【题解】洛谷P4852[非酋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也没咋写就放弃了。自己的心态还是得练练,毕竟以后写不来的比赛题多了去了(笑)
自己动态规划太菜,这种状态转移方程都毫无头绪。状态转移方程出来单调队列就显而易见了。

猜你喜欢

转载自blog.csdn.net/qq_41958841/article/details/82932719
今日推荐