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

  

posted @ 2022-05-07 19:36  cono奇犽哒  阅读(37)  评论(0编辑  收藏  举报