题目链接
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;
}
标签:1087,修剪,int,草坪,FJ,奶牛,define
From: https://www.cnblogs.com/zyyun/p/16961641.html