https://loj.ac/problem/10177

题目描述

  每个奶牛有一定效率,不能安排编号连续超过\(k\)头奶牛,求最大效率。

思路

  比较容易设计出\(dp\)的状态,我们用\(f[i][0/1]\)表示前\(i\)头奶牛第\(i\)头奶牛选/不选获得的最大效率。那么\(f[i][0]=max\{f[i-1][0],f[i-1][1]\}\),而\(f[i][1]=max\{\sum_{k=j}^{i}f[k][1]\}+a[i](i-m+1\le j\le i-1)\),表示从\(j\)开始选连续的一段以\(i\)为右端点的区间的最大值,为了能去掉内层循环,我们可以用前缀和以及单调队列优化掉,这样复杂度为\(O(N)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll read()
{
    ll res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res*w;
}
void write(ll x)
{
    if(x>9)write(x/10);
    putchar(x%10+'0');
}

ll f[100010][2],sum[100010],q[100010],pos[100010];
int main()
{
    int n=read(),k=read(),x;
    for(int i=1;i<=n;i++)
        x=read(),sum[i]=sum[i-1]+x;
    int head=1,tail=1;
    for(int i=1;i<=n;i++)
    {
        f[i][0]=max(f[i-1][0],f[i-1][1]);
        while(head<=tail&&pos[head]<i-k)head++;
        f[i][1]=f[pos[head]][0]-sum[pos[head]]+sum[i];
        while(head<=tail&&f[pos[tail]][0]-q[tail]<=f[i][0]-sum[i])tail--;
        q[++tail]=sum[i];pos[tail]=i;
    }
    write(max(f[n][0],f[n][1]));
}
01-07 19:46