1087. 修剪草坪

题目链接

1087. 修剪草坪

在一年前赢得了小镇的最佳草坪比赛后,FJ 变得很懒,再也没有修剪过草坪。

现在,新一轮的最佳草坪比赛又开始了,FJ 希望能够再次夺冠。

然而,FJ 的草坪非常脏乱,因此,FJ 只能够让他的奶牛来完成这项工作。

FJ 有 \(N\) 只排成一排的奶牛,编号为 \(1\)\(N\)

每只奶牛的效率是不同的,奶牛 \(i\) 的效率为 \(E_i\)

编号相邻的奶牛们很熟悉,如果 FJ 安排超过 \(K\) 只编号连续的奶牛,那么这些奶牛就会罢工去开派对。

因此,现在 FJ 需要你的帮助,找到最合理的安排方案并计算 FJ 可以得到的最大效率。

注意,方案需满足不能包含超过 \(K\) 只编号连续的奶牛。

输入格式

第一行:空格隔开的两个整数 \(N\)\(K\)

第二到 \(N+1\) 行:第 \(i+1\) 行有一个整数 \(E_i\)

输出格式

共一行,包含一个数值,表示 FJ 可以得到的最大的效率值。

数据范围

\(1 \le N \le 10^5\),
\(0 \le E_i \le 10^9\)

输入样例:

5 2
1
2
3
4
5

输出样例:

12

样例解释

FJ 有 5 只奶牛,效率分别为 1、2、3、4、5。

FJ 希望选取的奶牛效率总和最大,但是他不能选取超过 2 只连续的奶牛。

因此可以选择第三只以外的其他奶牛,总的效率为 1 + 2 + 4 + 5 = 12。

解题思路

单调队列优化dp

本题等价于选择权重和最小的数,使得不存在连续 \(k+1\) 个数没有被选中

  • 状态表示:\(f[i]\) 表示选择第 \(i\) 个数,且前 \(i\) 个数中连续 \(k+1\) 必须有一个数被选中

  • 状态计算:对于当前数是必选的,维护一个滑动窗口,滑动窗口大小为 \(k+1\)(针对前 \(i-1\) 个数而言),即要在滑动窗口中找权值最小的 \(f[j]\),更新 \(f[i]\),则有 \(f[i]=a[i]+f[j]\)

  • 时间复杂度:\(O(n)\)

代码

// Problem: 修剪草坪
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/1089/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5;
const LL inf=0x3f3f3f3f3f3f3f3f;
int n,k,a[N],q[N];
LL f[N],s;
int main()
{
    scanf("%d%d",&n,&k);
    int hh=0,tt=0;
    for(int i=1;i<=n;i++)
    {
    	scanf("%d",&f[i]);
    	s+=f[i];
    	while(hh<=tt&&i-1-q[hh]+1>k+1)hh++;
    	if(hh<=tt&&i>k-1)f[i]+=f[q[hh]];
    	while(hh<=tt&&f[q[tt]]>=f[i])tt--;
    	q[++tt]=i;
    }
    LL t=inf;
    if(n>=k+1)
    	for(int i=n-k;i<=n;i++)t=min(t,f[i]);
    if(t>inf/2)t=0;
    printf("%lld",s-t);
    return 0;
}
posted @ 2022-12-06 22:35  zyy2001  阅读(24)  评论(0编辑  收藏  举报