題目描述
在幻想鄉,琪露諾是以笨蛋聞名的冰之妖精。
某一天,琪露諾又在玩速凍青蛙,就是用冰把青蛙瞬間凍起來。但是這隻青蛙比以往的要聰明許多,在琪露諾來之前就已經跑到了河的對岸。於是琪露諾決定到河岸去追青蛙。
小河可以看作一列格子依次編號爲0到N,琪露諾只能從編號小的格子移動到編號大的格子。而且琪露諾按照一種特殊的方式進行移動,當她在格子i時,她只移動到區間[i+l,i+r]中的任意一格。你問爲什麼她這麼移動,這還不簡單,因爲她是笨蛋啊。
每一個格子都有一個冰凍指數A[i],編號爲0的格子冰凍指數爲0。當琪露諾停留在那一格時就可以得到那一格的冰凍指數A[i]。琪露諾希望能夠在到達對岸時,獲取最大的冰凍指數,這樣她才能狠狠地教訓那隻青蛙。
但是由於她實在是太笨了,所以她決定拜託你幫它決定怎樣前進。
開始時,琪露諾在編號0的格子上,只要她下一步的位置編號大於N就算到達對岸。
輸入輸出格式
輸入格式:
第1行:3個正整數N, L, R
第2行:N+1個整數,第i個數表示編號爲i-1的格子的冰凍指數A[i-1]
輸出格式:
一個整數,表示最大冰凍指數。保證不超過2^31-1
輸入輸出樣例
輸入樣例#1:
5 2 3 0 12 3 11 7 -2
輸出樣例#1:
11
說明
對於60%的數據:N <= 10,000
對於100%的數據:N <= 200,000
對於所有數據 -1,000 <= A[i] <= 1,000且1 <= L <= R <= N
分析
這題很容易就可以推出狀態轉移方程
f[x]=max{f[j]}+a[x];(i-r<=j<=i-l)
但如果只使用DP,時間複雜度爲O(n^2)
所以我們需要用一個單調隊列來維護
#include<iostream>
#include<stdio.h>
using namespace std;
int n,l,r,s[1000051],f[1000055];
int q[5000550],front,tail;
int main(){
cin>>n>>l>>r;
if(l>r) swap(l,r);
for(int i=0;i<=n;i++)
{
scanf("%d",&s[i]);
}
front=tail=1;
for(int i=l;i<=n+r;i++)
{
while(front<tail&&f[q[tail-1]]<f[i-l])
tail--;
q[tail++]=i-l;
while(front<tail&&q[front]<i-r)
front++;
f[i]=f[q[front]]+s[i];
}
int maxn=0;
for(int i=n;i<=n+r;i++)
{
maxn=max(maxn,f[i]);
}
cout<<maxn;
}