( ext{Solution:})
考虑(dp.)
(dp[i][j])表示前(i)个物品,锅里(j)个的最大值。
则(dp[i][j]=maxleft{dp[i-1][k]+a_i*j ight})
(dp[i][j]=maxleft{dp[i-1][k]+a_i*j ight})
(j-1leq kleq 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)值的一个前状态。