題目鏈接:https://www.luogu.org/problemnew/show/P1725
看了題後不難想到這個題是個dp,而狀態轉移方程爲dp[i] = max(dp[k]) (k >=i+l && k <= i+r) + a[i]。如果暴力去dp會多了一層(l,r)的循環,可能會超時,所以對區間(l,r)進行優化,用單調隊列進行優化。維護區間【l,r】的最大值即可。
#include <bits/stdc++.h>
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e6+7;
using namespace std;
int a[MAXN];
int dp[MAXN],q[MAXN]; //單調隊列存的是下標
int main() {
int n,l,r;
cin >> n >> l >> r;
for(int i = 0;i <= n;i++)
cin >> a[i];
int head = 1,tail = 0,p = 0;
int ans = -1;
memset(dp,-1,sizeof(dp)); //對於所有的點初始值都爲最小
dp[0] = 0;//在0點爲0
for(int i = l;i <= n;i++){ //從0開始,第一個能跳的點就是l,往後依次判斷
while(head <= tail && dp[q[tail]] < dp[p])
tail--; //如果當前隊列內的值小於最新的值,直接把他刪去即可
tail++;
q[tail] = p;//記錄是第幾個入隊的
if(q[head] + r < i) //如果此時隊頭的下標加上r比i小,要把隊頭刪去
head++;
dp[i] = dp[q[head]] + a[i];
p++;
}
for(int i = n-r+1;i <= n;i++) //對於能跳到對岸的點找一個最大值即可
ans = max(ans,dp[i]);
cout << ans << endl;
return 0;
}