LA 4327 Parade 单调队列dp

LA 4327

题意:F城由n+1个横向路和m+1个竖向路组成。你的任务是从最南边的路走到最北边的路,使得走过的路上的高兴值和最大(高兴值可能为负值)。同一段路不能经过两次,且不能从北往南走,在每条横向路所花时间不超过k。

思路:为了方便,从南往北走换成从北往南走,设d[ i ][ j ]为走到第( i , j )坐标时最大的高兴值,显然

d[ i ][ j ]=max(d[ i-1 ][ p ]+sum[ j ]-sum[ p ]),p 到 j 所花时间不超过 k,设f[ p ]=d[ i-1 ][ p ]-sum[ p ],那么怎么维护f[ p ]最大值呢,可用单调队列,每次更新一个 j 点,就把队列里f[ p ]值小于等于f[ j ]的值删除,然后把该点的值插入队列,注意的是该题要分从左到右和从右到左两个方向求d[ i ][ j ]的最大值。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std; 
int n,m,k;
int suma[105][10005],sumc[105][10005];
int d[105][10005];
int q[10005];
void get()
{
	for(int i=1;i<=n+1;i++)
	{
		suma[i][0]=0;
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&suma[i][j]);
			suma[i][j]+=suma[i][j-1];
		}
	}
	for(int i=1;i<=n+1;i++)
	{
		sumc[i][0]=0;
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&sumc[i][j]);	
			sumc[i][j]+=sumc[i][j-1];	
		}	
	}	
}
int main()
{
	while(~scanf("%d%d%d",&n,&m,&k)&&n&&m)
	{
		int i,j,p;
		get();
		int front,rear;
		for(i=1;i<=n+1;i++)
		{
			front=rear=0;
			q[0]=0;
			for(j=0;j<=m;j++)
			{			
				while(front<=rear&&sumc[i][j]-sumc[i][q[front]]>k)
				front++;
				d[i][j]=d[i-1][j];
				if(front<=rear)
				d[i][j]=max(d[i][j],d[i-1][q[front]]+suma[i][j]-suma[i][q[front]]);
				while(front<=rear&&d[i-1][j]>=d[i-1][q[rear]]+suma[i][j]-suma[i][q[rear]])
				rear--;
				q[++rear]=j;
			}
			rear=front=0;
			q[0]=m;
			for(j=m;j>=0;j--)
			{
				while(front<=rear&&sumc[i][q[front]]-sumc[i][j]>k)
				front++;
				if(front<=rear)
				d[i][j]=max(d[i][j],d[i-1][q[front]]+suma[i][q[front]]-suma[i][j]);
				while(front<=rear&&d[i-1][j]>=d[i-1][q[rear]]+suma[i][q[rear]]-suma[i][j])
				rear--;
				q[++rear]=j;
			}
		}
		int ans=0;
		for(i=0;i<=m;i++)
		ans=max(ans,d[n+1][i]);
		printf("%d\n",ans);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙橘子猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值