[笔记][题解]单调队列优化DP&lgP1725琪露诺

原题链

初始思路

这道题一看就是\(dp\)题,设\(f[x]\)是到\(x\)位置的最大冰冻效果,转移的话就是:\(f[x]=max(f[k])+val[x] -- k∈[x-r,x-l]\),但是由于数据范围的原因,裸的\(dp\)是不行的,我们发现我们求的是最大值,而且有转移方程是得知是一个最值加上一个定值,所以我们考虑维护这个最值,那么就自然地想到单调队列.

进阶思路

我们用单调队列维护最大值,就要保证队列的元素是单调递减的,在转移的时候也不用去找\(k∈[x-r,x-l]\)这个范围,直接去队列的队首元素即可.

代码

#include<bits/stdc++.h>
using namespace std;
int n,l,r,a[2000010],f[2000010];
int ans=-INT_MAX;
deque < int > q;
int main(){
	scanf("%d%d%d",&n,&l,&r);
	for(int i = 1;i <= 2 * n;i++)f[i] = -INT_MAX;
	for(int i = 0;i <= n;i++) scanf("%d",&a[i]);
	for(int i = 0;i <= n;i++){
		while(!q.empty() && f[i] > f[q.back()]) q.pop_back();
		q.push_back(i);
		while(!q.empty() && q.front() < i - r + l) 
			q.pop_front();//超过了可以跳跃的范围,就直接弹出
		f[i + l] = f[q.front()] + a[i + l];//单调队列维护的最大值在队头
	}
	for(int i = n + 1;i <= n + l;i++)//因为最终会跳出去,所以去外面找,初始化的时候也要注意多初始化一倍
		ans = max(ans,f[i]);
	printf("%d\n",ans);
	return 0;
}

posted @ 2020-10-23 10:34  czyczy  阅读(77)  评论(0编辑  收藏  举报