原题链接
[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 可以得到的最大的效率值。
5 2
1
2
3
4
5
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]),可以用单调队列维护。
单调队列不会?点这里。
所以这题我们就做出来了。
#include
#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);
}
更多方法