我用类似于最大字段和的思路,维护一个队列和这个队列的和 sum,使这个队列的和始终非负。当碰到一个新的值 a[i] 的时候,先更新队列,更新答案,将“过时”的数删去,更新队列和 sum 如果 a[i]+sum 小于 0 ,则清空队列,也就是这些数都不选了(因为选了肯定更小)。
结果只过了两个点
Code:
#include<bits/stdc++.h>
using namespace std;
void read(int &x){
int f=1;x=0;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar();}
x*=f;
}
#define N 500010
int n,m,ans,maxm;
int a[N];
int q[N],p[N],head,tail,tot;//tot记录队列和,p记录什么时候入队
int main(){
//freopen("P1714_2.in","r",stdin);
read(n),read(m);
for(int i=1;i<=n;i++){
read(a[i]);
maxm=max(maxm,a[i]);
}
if(maxm<0){//全负特殊情况,不能一块蛋糕都不吃
printf("%d ",maxm);
return 0;
}
head=1,tail=0;
for(int i=1;i<=n;i++){
while(p[head]<=i-m){
head++;
tot-=q[head];
}
if(tot+a[i]<=0){//归零队列
ans=max(ans,tot);
tot=0;
head=i+1,tail=i;
continue;
}
q[++tail]=a[i];
p[tail]=i;
tot+=a[i];
ans=max(ans,tot);//更新答案
}
cout<<ans;
}