虽然只是一道绿题,但也挺有意思的。
题意
你需要从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;
}