2442: [Usaco2011 Open]修剪草坪

Description


在一年前赢得了小镇的最佳草坪比赛后,FJ变得很懒,再也没有修剪过草坪。现在,
新一轮的最佳草坪比赛又开始了,FJ希望能够再次夺冠。

然而,FJ的草坪非常脏乱,因此,FJ只能够让他的奶牛来完成这项工作。FJ有N
(1 <= N <= 100,000)只排成一排的奶牛,编号为1...N。每只奶牛的效率是不同的,
奶牛i的效率为E_i(0 <= E_i <= 1,000,000,000)。

靠近的奶牛们很熟悉,因此,如果FJ安排超过K只连续的奶牛,那么,这些奶牛就会罢工
去开派对:)。因此,现在FJ需要你的帮助,计算FJ可以得到的最大效率,并且该方案中
没有连续的超过K只奶牛。

Input


* 第一行:空格隔开的两个整数N和K

* 第二到N+1行:第i+1行有一个整数E_i


Output


* 第一行:一个值,表示FJ可以得到的最大的效率值。

Sample Input

5 2
1
2
3
4
5

输入解释:

FJ有5只奶牛,他们的效率为1,2,3,4,5。他们希望选取效率总和最大的奶牛,但是
他不能选取超过2只连续的奶牛

Sample Output


12

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

HINT

 

Source

Gold

 

有两种思路。。。。

第一种:

用f[i]表示前i个的最大和,易得

f[i]=max(f[j]+sum[i]-sum[j+1])  (i>j>i-k)

然后朴素的做法会超时。。。然后可以把f[j]-sum[j+1]看做一项,记做b[j],就变成了f[i]=max(sum[i]+b[j])可以考虑队列优化。。。

然后就可以做辣!

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define mod 1000000007
13 #define inf 1000000000
14 #define maxn 100005
15 #define maxm 30005*2
16 #define eps 1e-10
17 #define ll long long
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
23 using namespace std;
24 int read(){
25     int x=0,f=1;char ch=getchar();
26     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
27     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 ll a[maxn],f[maxn],sum[maxn],q[maxn];
31 ll max1(ll a,ll b){
32     return a>b?a:b;
33 }
34 int main(){
35     //freopen("input.txt","r",stdin);
36     //freopen("output.txt","w",stdout);
37     int n=read(),k=read();
38     for1(i,n)a[i]=read(),sum[i]=sum[i-1]+a[i];
39     ll head=0,tail=1;q[0]=-1;q[1]=0;
40     for1(i,n){
41         while(head<=tail&&q[head]<i-k-1)head++;
42         f[i]=f[max1(0,q[head])]+sum[i]-sum[q[head]+1];
43         while(head<=tail&&f[max1(0,q[tail])]-sum[q[tail]+1]<=f[i]-sum[i+1])tail--;
44         q[++tail]=i;
45     }
46     cout<<f[n]<<endl;
47     return 0;
48 }
49 
View Code

 

第二种:

用f[i]表示前i个最少舍弃多大的数字,易得

f[i]=min(f[j]+a[i])  (i-j<=k)

再队列优化。。。

 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define mod 1000000007
13 #define inf 100000000000000ll
14 #define maxn 100005
15 #define maxm 30005*2
16 #define eps 1e-10
17 #define ll long long
18 #define for0(i,n) for(int i=0;i<=(n);i++)
19 #define for1(i,n) for(int i=1;i<=(n);i++)
20 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
21 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
22 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
23 using namespace std;
24 int read(){
25     int x=0,f=1;char ch=getchar();
26     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
27     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 ll a[maxn],f[maxn],sum,q[maxn];
31 ll minn(ll a,ll b){
32     return a<b?a:b;
33 }
34 int main(){
35     //freopen("input.txt","r",stdin);
36     //freopen("output.txt","w",stdout);
37     int n=read(),k=read();
38     for1(i,n)a[i]=read(),sum+=a[i];
39     ll head=0,tail=0;q[0]=0;
40     for1(i,n){
41         while(head<=tail&&q[head]<i-k-1)head++;
42         f[i]=a[i]+f[q[head]];
43         while(f[q[tail]]>f[i]&&head<=tail)tail--;
44         q[++tail]=i;
45     }
46     ll ans=inf;
47     for2(i,n-k,n)ans=minn(ans,f[i]);
48     cout<<sum-ans<<endl;
49     return 0;
50 }
View Code

 

posted @ 2016-03-18 10:06  HTWX  阅读(244)  评论(0编辑  收藏  举报