luoguP1725 琪露诺 单调队列
DP 方程:$f[i]=max(f[j])+v[i]$
转移范围:$i-r<=j<=i-l$
由此我们得知,每次只有 $[i-r,i-l]$ 部分的 $f$ 值对新更新的答案会有贡献. 故动态维护那个区间即可.
每次只会加入一个数,并弹出队首超出范围的数.
时间复杂度为 $O(n)$.
Code:
#include<cstdio> #include<deque> #include<algorithm> using namespace std; const int maxn = 400000+3; const long long inf = -1000000000; int n,l,r, w[maxn]; long long d[maxn]; struct Node{ int pos; long long val; Node(int pos=0,long long val=0):pos(pos),val(val){} }; deque<Node>Q; inline void update(int cur) { while(!Q.empty() && Q.front().pos < cur )Q.pop_front(); } inline void insert_x(Node a) { while(!Q.empty() && Q.front().val <= a.val)Q.pop_back(); Q.push_back(a); } int main(){ //freopen("in.txt","r",stdin); long long ans = inf; scanf("%d%d%d",&n,&l,&r); for(int i =0;i <= n;++i)scanf("%d",&w[i]); d[0] = w[0]; for(int i = 1;i<=n+l;++i){ int left = i-r, right = i-l; if(right < 0) d[i] = inf; else{ update(left); insert_x(Node(right,d[right])); d[i] =(long long) w[i] + Q.front().val; if(i>n) ans = max(ans, d[i]); } } printf("%lld",ans); return 0; }