题解 P1725 【琪露诺】
使用deque 实现的单调队列优化DP
(看了一眼题解里还没有利用双端队列容器实现的单调队列,求通过)
更好的阅读体验点这里:博客传送门
关于单调队列的
一道典型的
则
即
可以求得状态转移方程:
时间复杂度为
考虑如何优化:
显然对于求
用优先队列或者线段树?
单调队列,时间复杂度为
每次把一个
但如果某一次队头的元素的坐标已经不足以跳到当前点了,就要把队首
所以
那有没有可能在
现在要加入队列的元素坐标一定比队尾元素要大,而其值也比需要被
所以最优解不管怎么
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN = 200000 + 1;
int n, l, r;
int a[MAXN];
int f[MAXN];
struct Node {
int v, num;
};
deque<Node> q;
inline int read() {
int x=0, f=1; char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch == '-') f = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
x=(x<<3)+(x<<1)+ch-48, ch=getchar();
return x * f;
}
int main() {
n = read(), l = read(), r = read();
for(int i=0; i<=n; ++i)
a[i] = read();
int p = 0;
for(int i=l; i<=n; ++i) {
// 求max{f[i-r, i-l]}
// int maxn = 1 << 31;
// int s = i-r<0 ? 0 : i-r;
// for(int j=s; j<=i-l; ++j)
// maxn = max(maxn, f[j]);
while(!q.empty() && q.back().v < f[p])
q.pop_back();
q.push_back((Node){f[p], p});
while(q.front().num + r < i) q.pop_front();
f[i] = q.front().v + a[i];
++p;
}
int ans = 1 << 31;
for(int i=n-r+1; i<=n; ++i)
ans = max(ans, f[i]);
printf("%d\n", ans);
}