hdu4374(单调队列优化dp)

这题的转移很明显。

用dp[i][j] 表示到达i层j位置时的最大得分

sum[i][j] 表示第i层前j个数的和

dp[i][j] = max(max(dp[i - 1][j + k] + sum[i-1][j +k-1] - sum[i - 1][j - 1] + score[i][j]), max(dp[i - 1][j - k] - sum[i-1][j -k] + sum[i - 1][j] + score[i][j]))

因为只能移动t步,则就是在t长的窗口中的最小值


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int inf=0x3f3f3f3f;

inline int read()
{
	int x;
	scanf("%d",&x);
	return x;
}


int n,m,x,t;
int sco[105][10005],sum[105][10005],f[105][10005];
int q[10005],id[10005],head,tail;

void work()
{
	m=read();x=read();t=read();
	
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++) 
		sco[i][j]=read(),sum[i][j]=sum[i][j-1]+sco[i][j];
		
	for (int i=1;i<=m;i++) 
	if (i!=x) f[1][i]=-inf;else f[1][i]=sco[1][i];
	
	for (int i=2;i<=n+1;i++)
	{
		memset(q,0,sizeof(q));
		memset(id,0,sizeof(id));
		head=1;tail=1;
		q[1]=f[i-1][1]-sum[i-1][1];
		id[1]=1;//注意初始化,不要忘了id【1】之类的
		
		for (int j=1;j<=m;j++)
		{
			f[i][j]=-inf;
			while (head<=tail && id[head]<j-t) head++;
			
			f[i][j]=max(f[i][j],q[head]+sco[i][j]+sum[i-1][j]);
			
			while (head<=tail && q[tail]<=f[i-1][j+1]-sum[i-1][j+1]) tail--;
			q[++tail]=f[i-1][j+1]-sum[i-1][j+1];
			id[tail]=j+1;
		}
		
		/***********************************************/
		memset(q,0,sizeof(q));
		memset(id,0,sizeof(id));
		head=1;tail=1;
		q[1]=f[i-1][m]+sum[i-1][m-1];
		id[1]=m;
		
		for (int j=m;j>=1;j--)
		{
			while (head<=tail && id[head]>j+t) head++;
			
			f[i][j]=max(f[i][j],q[head]+sco[i][j]-sum[i-1][j-1]);
			
			while (head<=tail && q[tail]<=f[i-1][j-1]+sum[i-1][j-2]) tail--;
			q[++tail]=f[i-1][j-1]+sum[i-1][j-2];
			id[tail]=j-1;
		}
	}
	int ans=-inf;
	for (int i=1;i<=m;i++) ans=max(ans,f[n+1][i]);
	printf("%d\n",ans);
}
void clear()
{
	memset(sum,0,sizeof(sum));
	memset(sco,0,sizeof(sco));
	memset(f,0,sizeof(f));
}
int main()
{
	while (scanf("%d",&n)!=EOF)
	{
		clear();
		work();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值