【题目】
题目描述:
在一年前赢得了小镇的最佳草坪比赛后,FJ 变得很懒,再也没有修剪过草坪。现在,新一轮的最佳草坪比赛又开始了,FJ 希望能够再次夺冠。
然而,FJ 的草坪非常脏乱,因此,FJ 只能够让他的奶牛来完成这项工作。FJ 有 n ( 1 ≤ n ≤ 100 , 000 ) n(1≤n≤100,000) n(1≤n≤100,000) 只排成一排的奶牛,编号为 1 , 2 , . . . , n 1,2,...,n 1,2,...,n。每只奶牛的效率是不同的,奶牛 i i i 的效率为 e i ( 0 ≤ e i ≤ 1 , 000 , 000 , 000 ) e_i(0≤e_i≤1,000,000,000) ei(0≤ei≤1,000,000,000)。
靠近的奶牛们很熟悉,因此,如果 FJ 安排超过 k k k 只连续的奶牛,那么,这些奶牛就会罢工去开派对。因此,现在 FJ 需要你的帮助,计算 FJ 可以得到的最大效率,并且该方案中没有连续的超过 k k k 只奶牛。
输入格式:
第一行:空格隔开的两个整数 n n n 和 k k k
第二到 n + 1 n+1 n+1 行:第 i + 1 i+1 i+1 行有一个整数 e i e_i ei
输出格式:
一个值,表示 FJ 可以得到的最大的效率值。
数据样例:
输入
5 2
1
2
3
4
5
输出
12
提示:
【样例解释】
FJ 有 5 5 5 只奶牛,他们的效率为 1 1 1, 2 2 2, 3 3 3, 4 4 4, 5 5 5。他们希望选取效率总和最大的奶牛,但是他不能选取超过 2 2 2 只连续的奶牛
FJ 可以选择出了第三只以外的其他奶牛,总的效率为 1 + 2 + 4 + 5 = 12 1+2+4+5=12 1+2+4+5=12。
【分析】
我们可以转化一下问题,题目要我们最大化选出的奶牛的效率,我们可以最小化不选的奶牛的效率。
不难发现一个性质:两头相邻的不选的奶牛间最多只能有 k k k 头奶牛。
用 f i f_i fi 表示不选 i i i 时最小的效率,显然它可以从 f i − k − 1 f_{i-k-1} fi−k−1 ~ f i − 1 f_{i-1} fi−1 中转移过来。
但是直接暴力枚举来转移会超时,考虑用单调队列来优化 DP。
单调队列里面记录的是 f i f_i fi,是单调递增的,那么队首就是最小的,直接取队首来转移就可以了。
然后在 f n − k f_{n-k} fn−k ~ f n f_n fn 中取个最小值,再用总效率减去它即可。
【代码】
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
deque<int>q;
long long f[N];
int main()
{
int n,k,i,x;
long long sum=0,Min=1e+18;
scanf("%d%d",&n,&k);
q.push_back(0);
for(i=1;i<=n;++i)
{
scanf("%d",&x),f[i]=x,sum+=x;
while(!q.empty()&&i-q.front()>k+1) q.pop_front();
if(!q.empty()) f[i]=f[q.front()]+x;
while(!q.empty()&&f[i]<=f[q.back()]) q.pop_back();
q.push_back(i);
}
for(i=n-k;i<n;++i)
Min=min(Min,f[i]);
printf("%lld",sum-Min);
return 0;
}