Tyvj3980(dp+priority_queue)

题目链接

分析:
首先明确数据范围:
N<=10^5,A[i]<=10^9

这个题想的时间不短
显然留下的奶牛越多越好,那这就变成了一个剔除问题
对于每个i,如果选ta,那么之前k个中一定有一个不能选
我们可以枚举这个j(不能选的一个)
f[i]=max{f[j-1],sum(j+1,i)} (j-i<=k)
sum的计算可以通过前缀和求得
那么方程可化为:
f[i]=max{f[j-1]+aa[i]-aa[j]} (j-i<=k)
这样的话就是n^2的复杂度
显然会T
那我们就要考虑优化了,

我的思路到这里就戛然而止了,
于是看了一下学姐的blog
每次转移f[i]都要加aa[i]
那我们就需要快速找到max{f[j-1]-aa[j]}
优先队列优化
入队条件:因为我们是从前向后推得,后来的一定在时间上是更优的,那么如果值更大,我们就入队
出队条件:位置不符合(j-i<=k)

写完之后,交上去WA了两个点
看到学姐的代码中有这样一句:

f[i]=max(f[i-2]+a[i]-a[i-1])

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

tip

队列一定要有tou < wei
任何入队都要判断
在前k个的预处理中,也要统计答案
第九个点怎么也过不去。。。

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

int n,k;
ll a[100010],ans=0,f[100010],q[100010][2];
int tou=0,wei=0;   
//第i个奶牛选,前面有j个连续的奶牛工作(包括ta) 

int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]),a[i]+=a[i-1],q[i][1]=-99999999;
    int i,j,l;
    wei=0,tou=1;
    for (i=1;i<=k;i++) 
    {
        f[i]=a[i];
        int x=f[i]-a[i+1];
        while (q[wei][1]<=x&&tou<=wei) wei--;
        q[++wei][0]=i;
        q[wei][1]=x;
        ans=max(ans,f[i]);
    }
    for (i=k+1;i<=n;i++)
    {
        while (i-q[tou][0]-1>k&&tou<=wei) tou++;
        //因为队列中的元素是 f[i]-a[i+1],所以判断变成了i-q[tou][0]-1 
        f[i]=max(f[i],q[tou][1]+a[i]);
        f[i]=max(f[i],f[i-2]+a[i]-a[i-1]);
        //这里很重要,之所以加上 f[i-2]+a1[i]-a1[i-1]是因为需要特殊考虑k==1 的情况
        int x=f[i]-a[i+1];
        while (q[wei][1]<=x&&tou<=wei) wei--;
        q[++wei][0]=i;
        q[wei][1]=x;
        ans=max(ans,f[i]);
    }
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673184.html