分析:
首先明确数据范围:
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;
}