【Usaco 2011 Open】修剪草坪

【题目】

传送门

题目描述:

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

然而,FJ 的草坪非常脏乱,因此,FJ 只能够让他的奶牛来完成这项工作。FJ n ( 1 ≤ n ≤ 100 , 000 ) n(1≤n≤100,000) n(1n100,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(0ei1,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} fik1 ~ f i − 1 f_{i-1} fi1 中转移过来。

但是直接暴力枚举来转移会超时,考虑用单调队列来优化 DP

单调队列里面记录的是 f i f_i fi,是单调递增的,那么队首就是最小的,直接取队首来转移就可以了。

然后在 f n − k f_{n-k} fnk ~ 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值