BZOJ2442 || 洛谷P2627 [Usaco2011 Open]修剪草坪【单调队列优化DP】

Time Limit: 10 Sec
Memory Limit: 128 MB

Description

在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪。现在,
新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠。

然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作。FJ有N
(1 <= N <= 100,000)只排成一排的奶牛,编号为1…N。每只奶牛的效率是不同的,
奶牛i的效率为E_i(0 <= E_i <= 1,000,000,000)。

靠近的奶牛们很熟悉,因此,如果FJ安排超过K只连续的奶牛,那么,这些奶牛就会罢工
去开派对:)。因此,现在FJ需要你的帮助,计算FJ可以得到的最大效率,并且该方案中
没有连续的超过K只奶牛。

Input

第一行:空格隔开的两个整数N和K
第二到N+1行:第i+1行有一个整数E_i

Output

第一行:一个值,表示FJ可以得到的最大的效率值。


题目分析:

我们把问题转化成从序列中删除奶牛来考虑
即从整个序列中删去若干个奶牛使得符合题目条件

d p [ i ] 表示考虑 1 i 位置的奶牛,且强制删除 i 号奶牛所减少的最少效率
可能有点拗口

那么有转移方程
d p [ i ] = m i n ( d p [ j ] + E i ) ( i k 1 <= j <= i 1 )
即保证上一个删除的奶牛与当前删除的奶牛之间留下不超过k个奶牛

直接枚举 O ( n 2 ) 肯定超时,所以用单调队列优化变成 O ( n )

最后 a n s = s u m m i n ( d p [ i ] ) ( n k <= i <= n )
既保证最后删除的奶牛与到序列末端不超过k个
这样就同时保证了 1 i i n 的合法性


#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;

lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=100010;
lt n,k;
lt dp[maxn];
lt q[maxn],ll,rr;
lt sum,ans=2e60;

int main()
{
    n=read();k=read();
    for(int i=1;i<=n;++i)
    dp[i]=read(),sum+=dp[i];

    ll=rr=1;
    for(int i=1;i<=n;++i)
    {
        while(ll<rr&&q[ll]<i-k-1)++ll;
        if(i>=k+2)dp[i]+=dp[q[ll]];
        //注意从k+2开始更新,因为1-k+1中只删除自己就肯定合法
        while(ll<rr&&dp[i]<=dp[q[rr-1]])--rr;
        q[rr++]=i;
    }
    for(int i=n-k;i<=n;++i)
    ans=min(ans,dp[i]);
    printf("%lld",sum-ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/81077923