修剪草坪 单调队列优化DP

// 修剪草坪.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cstring>
#include <deque>
using  namespace std;

/*
https://loj.ac/p/10177
http://ybt.ssoier.cn:8088/problem_show.php?pid=1599

原题来自:USACO 2011 Open Gold

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

然而,FJ 的草坪非常脏乱,因此,FJ 只能够让他的奶牛来完成这项工作。FJ 有 N只排成一排的奶牛,编号为 1到 N。
每只奶牛的效率是不同的,奶牛 i 的效率为 Ei。

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

【输入】
第一行:空格隔开的两个整数 N 和 K;

第二到 N+1 行:第 i+1行有一个整数 Ei。

【输出】
一行一个值,表示 FJ 可以得到的最大的效率值。

【输入样例】
5 2
1
2
3
4
5
【输出样例】
12
【提示】
样例说明:

FJ 有 5
 只奶牛,他们的效率为 1,2,3,4,5。
 他们希望选取效率总和最大的奶牛,但是他不能选取超过 2
 只连续的奶牛。FJ 选择出了第三只以外的其他奶牛,总的效率为 1+2+4+5=12。

数据范围与提示:

对于全部数据,1≤N≤105,0≤Ei≤109。



6 1
4
7
2
0
8
9

10 3
16
28
37
8
47
30
36
6
0
37


237
*/


const int N = 100010;
long long pre[N];
long long dp[N];
int lastZero;
int n, k;


int main()
{
	cin >> n >> k;

	for (int i = 1; i <= n; i++) {
		int t; cin >> t;
		pre[i] = pre[i - 1] + t;
	}
	deque<int> q;
	for (int i = 1; i <= n; i++) {
		/*
		if (i <= k) {
			dp[i] = pre[i];
		}
		else {
			for (int lastzero = i; lastzero >= i - k; lastzero--) {
				dp[i] = max(dp[i], dp[lastzero - 1] + pre[i] - pre[lastzero]);
			}
		}
		*/
		while (!q.empty() && i - q.front() > k) 
			q.pop_front();
		if (q.empty() || i<=k) 
			dp[i] = pre[i];
		else {
			dp[i] = (dp[q.front()-1] - pre[q.front()] + pre[i]);
		}

		while (!q.empty() && (dp[q.back()-1] - pre[q.back()] <= dp[i-1] - pre[i])) 
			q.pop_back();
		q.push_back(i);
	}

	cout << dp[n] << endl;

	return 0;
}

posted on 2024-06-20 15:37  itdef  阅读(2)  评论(0编辑  收藏  举报

导航