P1725 琪露诺 - 单调队列优化dp

虽然只是一道绿题,但也挺有意思的。

题意

你需要从0跳到n,每个点上有价值A[i],到达一个点就能得到A[i]价值,但是你每次只能跳到 [ i + l , i + r ] [i+l,i+r] [i+l,i+r]上,问超过终点的最大价值是多少。

朴素的dp很好写,当然,速度也很拉跨。我们能发现每次转移到i的点都是在[i-r,i-l]间的,这个可以用一个单调队列来维护,那么唯一要解决的问题就是入队时我们要保证队列内没有pos>i-l的,这一点我们可以延迟入队,在遍历第i个点时再推入i-l,就解决了这个问题。

#include "bits/stdc++.h"

using namespace std;
const int N = 3e5 + 100;
int sc[N];
int dp[N];
int q[N];
void solve() {
    
    
    int n,l,r;
    cin >> n >> l >> r;
    for (int i = 0; i <= n; ++i) {
    
    
        cin >> sc[i];
    }
    memset(dp,0xcf,sizeof dp);
    memset(q,-1,sizeof q);
    dp[0] = sc[0];
    int head = 1;
    int tail = 0;
    for (int i = 0; i <= n+r; ++i) {
    
    
        while (head <= tail && q[head] < i - r) head++;
        while (head <= tail &&  i - l >= 0 &&dp[q[tail]] < dp[i-l]) tail--;
        if (i - l >= 0)
        q[++tail] = i - l;
        if (q[head] != -1)
        dp[i] = max(dp[i],sc[i]+dp[q[head]]);

    }
    int ma = -0x3f3f3f3f3f;
    for (int i = n; i <= n+r; ++i) {
    
    
        ma = max(ma,dp[i]);
    }
    cout << ma << endl;
}

signed main() {
    
    
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_45509601/article/details/119461552
Recommended