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;
}

浙公网安备 33010602011771号