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
]
dp[i]
dp[i]表示考虑前
i
i
i 个奶牛,且强制删除
i
i
i 号奶牛所减少的最少效率
可能有点拗口
那么有转移方程
d
p
[
i
]
=
m
i
n
(
d
p
[
j
]
+
E
i
)
(
i
−
k
−
1
<
=
j
<
=
i
−
1
)
dp[i]=min(dp[j]+E_i)(i-k-1<=j<=i-1)
dp[i]=min(dp[j]+Ei)(i−k−1<=j<=i−1)
即保证上一个删除的奶牛与当前删除的奶牛之间留下不超过k个奶牛
直接枚举 O ( n 2 ) O(n^2) O(n2)肯定超时,所以用单调队列优化变成 O ( n ) O(n) O(n)
最后
a
n
s
=
s
u
m
−
m
i
n
(
d
p
[
i
]
)
(
n
−
k
<
=
i
<
=
n
)
ans=sum-min(dp[i])(n-k<=i<=n)
ans=sum−min(dp[i])(n−k<=i<=n)
既保证最后删除的奶牛与到序列末端不超过k个
这样就同时保证了
1
1
1~
i
i
i 与
i
i
i~
n
n
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;
}