tyvj 修剪草坪

来源:互联网 发布:装置艺术 网站 知乎 编辑:程序博客网 时间:2024/06/08 11:19
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);
}//动态规划+单调队列优化

0 0
原创粉丝点击