P5858 「SWTR-03」Golden Sword
题目描述
制造一把金宝剑需要 n 种原料,编号为 1 到 n,编号为 i 的原料的坚固值为 ai。
炼金是很讲究放入原料的顺序的,因此小 E 必须按照 1到 n 的顺序依次将这些原料放入炼金锅。
但是,炼金锅的容量非常有限,它最多只能容纳 w个原料。
所幸的是,每放入一个原料之前,小 E 可以从中取出一些原料,数量不能超过 s 个。
- 我们定义第 i 种原料的耐久度为:放入第 i种原料时锅内的原料总数(包括正在放入的原料) × ai,则宝剑的耐久度为所有原料的耐久度之和。
小 E 当然想让他的宝剑的耐久度尽可能得大,这样他就可以带着它进行更多的战斗,请求出耐久度的最大值。
注:这里的“放入第 i 种原料时锅内的原料总数包括正在放入锅中的原料,详细信息请见样例。
思路: dp,每次通过上一轮i-1,原料数区间为[j+s-1,j-1]里选出最大的来松弛,然后这里的最大值是连续固定长度的区间最大值,可以用单调队列来做,不然O(m^2)*n的复杂度太高了呀
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5005; ll a[maxn]; ll f[maxn]; ll q[maxn],l,r; ll p[maxn]; int main(){ int n,w,s; cin>>n>>w>>s; for(int i=1;i<=n;i++){ cin>>a[i]; } memset(f,0xf3,sizeof(f));//初始值为负数 f[0]=0; for(int i=1;i<=n;i++){ l=r=1; p[l]=w; q[r]=f[w]; for(int j=w;j>0;j--){ while(l<=r&&q[r]<f[j-1])r--;//单调队列来求 while(l<=r&&p[l]-j>=s)l++; p[++r]=j-1; q[r]=f[j-1]; f[j]=q[l]+j*a[i]; } } ll res=INT_MIN; for(int i=1;i<=w;i++){ res=max(res,f[i]); } cout<<res<<endl; }