【题解】「SWTR-03」Golden Sword
\(\text{Solution:}\)
考虑\(dp.\)
\(dp[i][j]\)表示前\(i\)个物品,锅里\(j\)个的最大值。
则\(dp[i][j]=\max\left\{dp[i-1][k]+a_i*j\right\}\)
\(dp[i][j]=\max\left\{dp[i-1][k]+a_i*j\right\}\)
\(j-1\leq k\leq \min\{w,j+s-1\}\)
故而单调队列,因为\(s\)取值有限度。
单调队列中维护的是决策点的位置,判断时可以直接判断是不是在更新范围内。调用时找到对应\(dp\)值即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,w,s,a[20010],dp[5505][5505],head,tail,q[5505];
inline int Max(int x,int y){return x>y?x:y;};
inline int Min(int x,int y){return x<y?x:y;};
signed main(){
scanf("%lld%lld%lld",&n,&w,&s);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
memset(dp,-0x3f,sizeof dp);
dp[0][0]=0;
for(int i=1;i<=n;++i){
head=1,tail=0;q[++tail]=w;
for(int j=w;j;--j){
while(head<=tail&&q[head]>j+s-1)head++;
while(head<=tail&&dp[i-1][q[tail]]<=dp[i-1][j-1])--tail;
q[++tail]=j-1;
dp[i][j]=dp[i-1][q[head]]+j*a[i];
}
}
int ans=-1e18;
for(int i=1;i<=w;++i)ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
}
注意决策的更新要在更新当前值之前,来保证必然有一个来更新当前\(dp\)值的一个前状态。