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;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/11041484.html