【题解】「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\)值的一个前状态。

posted @ 2020-10-21 22:18  Refined_heart  阅读(96)  评论(0编辑  收藏  举报