Tyvj3980(dp+priority_queue)

来源:互联网 发布:淘宝第四层级金额 编辑:程序博客网 时间:2024/06/05 18:52

题目链接

分析:
首先明确数据范围:
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 longusing 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;}
原创粉丝点击