题目
[USACO11OPEN] Mowing the Lawn G
题目描述
在一年前赢得了小镇的最佳草坪比赛后,Farmer John 变得很懒,再也没有修剪过草坪。现在,新一轮的最佳草坪比赛又开始了,Farmer John 希望能够再次夺冠。
然而,Farmer John 的草坪非常脏乱,因此,Farmer John 只能够让他的奶牛来完成这项工作。Farmer John 有
N
N
N(
1
≤
N
≤
1
0
5
1\le N\le 10^5
1≤N≤105)只排成一排的奶牛,编号为
1
…
N
1\ldots N
1…N。每只奶牛的效率是不同的,奶牛
i
i
i 的效率为
E
i
E_i
Ei(
0
≤
E
i
≤
1
0
9
0\le E_i\le 10^9
0≤Ei≤109)。
靠近的奶牛们很熟悉,因此,如果 Farmer John安排超过
K
K
K 只连续的奶牛,那么,这些奶牛就会罢工去开派对 😃。因此,现在 Farmer John 需要你的帮助,计算 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。
输出格式
第一行:一个值,表示 Farmer John 可以得到的最大的效率值。
样例 #1
样例输入 #1
5 2
1
2
3
4
5
样例输出 #1
12
解题思路
分析
我们转换一下题目,即给定一个序列
a
1
,
2
,
3
,
…
,
n
a_{1,2,3, \dots ,n}
a1,2,3,…,n,和一个整数
k
k
k,要求每
k
k
k 个数中最少删除一个数。
考虑DP:
令
f
[
i
]
f[i]
f[i] 表示算到
a
i
a_i
ai 时的最小删除和。
则很容易得转移方程:
f
[
i
]
=
min
(
f
[
i
−
1
]
,
f
[
i
−
2
]
,
…
,
f
[
i
−
k
+
1
]
)
+
E
[
i
]
f[i]=\min{(f[i-1],f[i-2],\dots,f[i-k+1])}+E[i]
f[i]=min(f[i−1],f[i−2],…,f[i−k+1])+E[i]
初始化
f
[
i
]
f[i]
f[i] 为正无穷大,
f
[
1
]
=
E
[
1
]
f[1]=E[1]
f[1]=E[1]
时间复杂度: O ( N K ) = O ( N 2 ) O(NK)=O(N^2) O(NK)=O(N2)
考虑优化:
显然,对于
min
(
f
[
i
−
1
]
,
f
[
i
−
2
]
,
…
,
f
[
i
−
k
+
1
]
)
\min{(f[i-1],f[i-2],\dots,f[i-k+1])}
min(f[i−1],f[i−2],…,f[i−k+1]),可以用单调队列维护。
单调队列不会?点这里。
所以这题我们就做出来了。
Code
#include<bits/stdc++.h>
#define int long long
const int N=1e6+1;
int n,m,a[N],q[N],f[N],s[N],o;
signed main()
{
scanf("%lld%lld",&n,&m);
m++;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),o+=a[i];
int h=1,t=0;
int ans=1e18;
for(int i=1;i<=n;i++)
{
while(h<=t&&i-m>q[h])
h++;
while(h<=t&&f[q[t]]>=f[i-1])
t--;
q[++t]=i-1;
f[i]=f[q[h]]+a[i];
}
for(int i=n-m+1;i<=n;i++)
ans=std::min(ans,f[i]);
printf("%lld",o-ans);
}