[codevs4654][bzoj2442]修剪草坪(单调队列dp)

24 篇文章 0 订阅

题目:

我是超链接

题解:

启明星:这题目不就是核电站?如果连起来k个就会boom,只不过那里要求填尽量多的地雷,这里要权值尽量大而已。别的处理就是一样了?
f[i][j]表示前i个已经连续了j个的最大权值
如果j!=0,是从f[i-1][j-1]转移的;如果j=0,那就从f[i-1][0..k-1]中的最大值转移过来的
好像空间时间都会boom,我们怎么办呢?好像可以运用滚动数组+prority_queue优化——60pts
Emmm….这个MLE是…?哦我queueboom了,那只能手动队列了,等等,队列个P啊,为什么不手动维护最大值?这个WA好像是要用longlong?
改改改
好了第二波,Emmm….好了那些MLE的WA的现在全T了
这个1e5^2很不稳啊(这不是废话吗),运用累加思想,这一次长度到j的就是上一次j-1的加上a[i]?

逃避三天之后
阳:看来要换思路了f[i]表示前i个元素(第i个不选)的最小不选值
f[i]=min{f[j]}+a[i] 限制就是j∈[i-k+1,i-1] 这个O(nk)的效率很不ok啊
这个j明显在i之前就不会改变了【仿佛看到了昨天某题的影子
单调队列优化?就是把f[j]弄到队列中,提取就是最小值(单减的队列
最后给ans找个max
注意:这个f[i]更新的f[j]范围是到i-1,所以要把f[i]的赋值语句放到最前面;对于不到k项的元素,ta们一定会在队首,为了避免f[i] (i <= k) 被ta更新,事先给队列放一位元素0,在读满k位之前,不把0t出去

代码:

#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
struct hh{LL tim,z;}q[100005];
int a[100005];
LL f[100005];
int main()
{
    LL sum=0,ans=0;
    int n,k,i;
    scanf("%d%d",&n,&k);
    for (i=1;i<=n;i++) scanf("%d",&a[i]),sum+=(LL)a[i];
    int head=1,tail=1;
    for (i=1;i<=n;i++)
    {
        f[i]=q[head].z+a[i];
        while (q[tail].z>=f[i] && head<tail) tail--;
        q[++tail].z=f[i]; q[tail].tim=i;
        while (q[head].tim<=i-k-1 && head<tail) head++;
    }
    for (i=n-k;i<=n;i++) ans=max(ans,sum-f[i]);
    printf("%lld",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值