您的位置:首页 > 其它

tyvj 修剪草坪

2016-01-09 18:43 274 查看
P3980 修剪草坪From: wwqk4444

时间: 1000ms / 空间: 125536KiB / Java类名: Main


描述

约翰让他的奶牛来修建草坪。他有 N 头奶牛,第 i 头奶牛的工作能力为 Ai。编号相近的奶牛很熟悉,如果同时让 K + 1 头编号连在一起的奶牛工作,她们就会密谋罢工。请问,约翰应该让哪些奶牛同时工作,使得它们的能力之和最大,而且不会罢工。

输入格式

• 第一行:两个整数 N 和 K,1 ≤ K ≤ N ≤ 10^5

5

• 第二行到 N + 1 行:第 i + 1 行有一个整数 Ai,1 ≤ Ai ≤ 10^9

9

输出格式

• 单个整数,表示在所有不会罢工的奶牛组合之中,最大的能力之和

样例输入

5 2

1

2

3

4

5

样例输出

12

解释

除了第三头以外的所有奶牛都工作,总能力

为 1 + 2 + 4 + 5 = 12

这是裸DP:

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

long long f[110000],a1[110000];

int n,m,i,j,a[110000];

int main()

{

scanf("%d%d",&n,&m);

for (i=1;i<=n;i++)

scanf("%d",&a[i]);

for (i=1;i<=n;i++)

{

a1[i]=a1[i-1]+a[i];//A1中存储的是从1加到i的总和;

}

memset(f,0,sizeof(f));

f[0]=0;

f[1]=a[1];

for (i=2;i<=n;i++)

{

int k=i-m;

for (j=max(k,0);j<=i-1;j++)//枚举上一次断开的点

{

long long l=0;

if (j-1>0)

{

l=f[j-1]+a1[i]-a1[j];

}

else

{

l=a1[i]-a1[j];

}

f[i]=max(f[i],l);

}

}

long long ans=0;

for (i=1;i<=n;i++)

ans=max(ans,f[i]);

printf("%lld",ans);

}//DP方程:f[i]=f[j-1]+a1[i]-a1[j] 观察方程可以发现每次都需要加上a1[i],那么就需要从符合要求的范围内找出最大的f[j-1]-a1[j],这里用单调队列,是优化的关键

这是AC代码

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

long long f[110000],a1[110000],ans;

int n,m,i,j,a[110000];

int head,tail;

long long q[110000],p[110000];//注意数据范围

int main()

{

scanf("%d%d",&n,&m);

for (i=1;i<=n;i++)

scanf("%d",&a[i]);

for (i=1;i<=n;i++)

{

a1[i]=a1[i-1]+a[i];

p[i]=-99999999;

}

head=1; tail=0;

for (i=1;i<=m;i++)

{

f[i]=a1[i];

while(f[i]-a1[i+1]>=p[tail]&&head<=tail) tail--;

p[++tail]=f[i]-a1[i+1];

q[tail]=i;

ans=max(ans,f[i]);

}

for (i=m+1;i<=n;i++)

{

while (i-q[head]-1>m) head++;

f[i]=max(f[i-2]+a1[i]-a1[i-1],p[head]+a1[i]);//这里很重要,之所以加上 f[i-2]+a1[i]-a1[i-1]是因为需要特殊考虑k==1
的情况

while(f[i]-a1[i+1]>=p[tail]&&head<=tail) tail--;

p[++tail]=f[i]-a1[i+1];

q[tail]=i;

ans=max(ans,f[i]);

}

printf("%lld",ans);

}//动态规划+单调队列优化
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: