概述
题目描述
在一年前赢得了小镇的最佳草坪比赛后,约翰变得懒惰了,再也没有修剪过草坪。现在,新一轮的比赛又开始了,约翰希望能够再次夺冠。然而,约翰家的草坪非常脏乱,因此,约翰需要让他的奶牛来完成这项工作。约翰家有N头奶牛,排成一直线,编号为1到N。每只奶牛的能力是不同的,第i头奶牛的能力为Ei。靠在一起的奶牛很熟悉,所以如果安排相邻的K+1头奶牛一起工作,她们就会密谋罢工,所以不能选中连续的K+1头奶牛。因此,约翰需要你的帮助。如何挑选奶牛,才能使她们的能力之和最高呢?
输入
第一行:两个用空格隔开的整数:
N
N
N和
K
K
K,
1
≤
N
≤
100000
,
1
≤
K
≤
N
1≤ N≤ 100000,1≤ K≤ N
1≤N≤100000,1≤K≤N
第二行到
N
+
1
N+1
N+1行:第
i
+
1
i+1
i+1行有一个整数,表示第i头牛的能力
E
i
,
1
≤
E
i
<
=
1
0
9
Ei,1≤ Ei <= 10^9
Ei,1≤Ei<=109
输出
第一行:单个整数,表示最大的能力之和
样例输入
5 2
1
2
3
4
5
样例输出
12
数据范围限制
对于30% 的数据,有
1
≤
n
≤
10
1 ≤ n ≤ 10
1≤n≤10。
对于60% 的数据,有
1
≤
n
≤
2
,
000
1 ≤ n ≤ 2, 000
1≤n≤2,000。
对于100% 的数据,有
1
≤
n
≤
100
,
000
1 ≤ n≤ 100, 000
1≤n≤100,000。
提示
除了第三头以外的所有奶牛都选,总能力为 1 + 2 + 4 + 5 = 12 1+2+4+5=12 1+2+4+5=12
思路
很(不)显然,这是一道
D
P
DP
DP(!!!)
设
f
i
f_i
fi 是到第i头牛的最优解
那么,从第
i
−
k
i-k
i−k头牛到第i头牛肯定有一头牛
j
j
j不能选 (好惨一牛的),j就是这
k
+
1
k+1
k+1头牛的断点
- f [ i ] = m a x ( f [ i − 1 ] , f [ j − 1 ] + a [ j + 1 ] + a [ j + 2 ] + . . . + a [ i ] ) f[i]=max(f[i-1],f[j-1]+a[j+1]+a[j+2]+...+a[i]) f[i]=max(f[i−1],f[j−1]+a[j+1]+a[j+2]+...+a[i])
如果用前缀优化一下,那么就是
- f [ i ] = m a x ( f [ i − 1 ] , f [ j − 1 ] + a [ i ] − a [ j ] ) ; f[i]=max(f[i-1],f[j-1]+a[i]-a[j]); f[i]=max(f[i−1],f[j−1]+a[i]−a[j]);
我们小小的变形一下
- f [ i ] = m a x ( f [ i − 1 ] , f [ j − 1 ] − a [ j ] ) + a [ i ] ; f[i]=max(f[i-1],f[j-1]-a[j])+a[i]; f[i]=max(f[i−1],f[j−1]−a[j])+a[i];
发现max里面的值只与j有关,所以可以用单调队列优化转移。
雷锋帮助
(作为一个蒟蒻,)我相信我以后肯定看不懂单调队列优化,然后还要回来搜自己写的单调队列优化,so,我来给未来的自己举个栗子。。。
单调队列就是单调递增或者单调递减
有四头牛,他们分别是老大、老二、老三、老四。选牛时,前三个选了,到老四了。嗯~ TA比老三小(选的晚),但是TA比老三巨,所以,老三可以退役了。诶~ 发现老四虐不过老二,那就停止虐菜。好的ヽ( ̄▽ ̄)و,再看老大,发现TA虽然比的其他几个巨,但是TA光荣退役了(不在i-k到i的范围内)。返回一个最巨的,当然是老二啦 (膜拜)。
#include<iostream>
#include<cstdio>
using namespace std;
long long a[100100],f[100100],d[100100],n,k;//d是单调队列,f是DP,a是前缀和;
int q[100100],h=1,t=1;//q是队列,h=head,t=tail
long long demo(int i){//让返回值尽量的大,队列单调减,使首元素恒最大
d[i]=f[i-1]-a[i];//设个初值
while(h<=t&&d[q[t]]<d[i])--t;//开始虐菜
q[++t]=i;//加入dalao光荣榜
while(h<=t&&q[h]<i-k)h++; //大佬退役
return d[q[h]];//返回最大值
}
int main(){
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]+=a[i-1];//前缀处理
}
for(int i=1;i<=n;i++)
f[i]=demo(i)+a[i];
printf("%lld",f[n]);
}
最后
以上就是负责小蘑菇为你收集整理的【DP】【单调队列优化】修剪草坪的全部内容,希望文章能够帮你解决【DP】【单调队列优化】修剪草坪所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复