Codeforces Round #521 (Div. 3) F2 單調佇列dp
阿新 • • 發佈:2018-12-22
題意:給你n個有權值的點,你從位置0開始,每次操作可以跳到當前位置+k範圍內的點並獲得其權值(不能跳到原點),要求必須操作x次,且最後的位置+k必須要大於n,求可以獲得的最大權值。
思路:設d[ i ][ j ]為經過 j 次操作到達第 i 個位置所獲得的最大權值,方程很容易想到 d[ i ][ j ]=max(d[ p ][ j-1 ])+a[ i ],p+k>=i,但是這個方程複雜度是n*x*k,過不了這題,但是我們可以用單調遞減佇列去維護d[ p ][ j-1 ]的值,複雜度就降低成了n*k。
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=5005; int a[maxn]; ll d[maxn][maxn]; int q[maxn]; int main() { int n,k,x; scanf("%d%d%d",&n,&k,&x); for(int i=1;i<=n;i++) scanf("%d",&a[i]); if(k*x+k-1<n||x>n) { puts("-1"); return 0; } ll ans=0; d[0][0]=1; for(int j=1;j<=x;j++) { int front=1,rear=0; q[++rear]=j-1; for(int i=j;i<=n;i++) { while(front<=rear&&q[front]+k<i)front++; if(front<=rear&&d[q[front]][j-1]!=0) d[i][j]=d[q[front]][j-1]+a[i]; while(front<=rear&&d[q[rear]][j-1]<=d[i][j-1])rear--; q[++rear]=i; if(j==x&&i+k>n) ans=max(ans,d[i][j]); } } cout<<ans-1; }