BZOJ2442 [Usaco2011 Open]修剪草坪 (DP+单调队列)

BZOJ2442 [Usaco2011 Open]修剪草坪

Description

给定一个n(n<=1000000)个数的正整数序列,要求选取的数连续不超过k,问最大选取值为多少。

题解

因为序列是正整数,所以我们每次空着不选的长度一定是1。
于是我们可以很容易地推出状态转移方程。
钦定f[i]为序列到i,且第i位不选的最大答案,用sum[i]表示前缀和
我们有

f[i]=max(f[i],f[j]+sum[i1]sum[j])     (max(ik1,0)<=j<k)

可是这样的复杂度是 O(n2) ,会超时。
所以我们得想办法优化。
观察状态转移方程,我们发现选取的数是一个长度为k的区间的f[i]-sum[j]的最大值再加上sum[i-1]。所以可以用单调队列来优化,这样的复杂度就减小到了O(n)。

#include <cstdio>
#include <cmath>
#include <queue>
#include <algorithm>
#include <cstring>
#define MAXN 100000+10
#define LL long long
using namespace std;
int k,n,t,h;
LL f[MAXN],a[MAXN],sum[MAXN],ans;
struct Date{
    LL n,c;
}q[MAXN];
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]+=sum[i-1]+a[i];
    for(int i=1;i<=n+1;i++)
    {
        while(q[h].n<i-k-1) h++;
        f[i]=max(f[i],q[h].c+sum[i-1]);
        while(f[i]-sum[i]>=q[t].c&&t>=h) q[t].c=q[t].n=0,t--;
        q[++t].c=f[i]-sum[i];q[t].n=i;
        ans=max(f[i],ans);
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值