EZOJ #88
分析
自然想到二分
我们二分一个长度,之后考虑如何线性判断是否合法
我们可以维护一个单调队列表示从i开始的长度为d的区间和的最大值
每次用一段区间和减去它包含的长度为d的区间最大值即可
但是我们发现这个数据范围有那么一点点会t的征兆
于是我们考虑消除掉二分的log
于是我们继续用单调队列维护,用双指针扫一下就可以了
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
inline int ra(){
int x=0,f=1;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s))x=(x<<3)+(x<<1)+(s-'0'),s=getchar();
return x*f;
}
inline long long ra2(){
long long x=0,f=1;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s))x=(x<<3)+(x<<1)+(s-'0'),s=getchar();
return x*f;
}
long long pre[1000100],del[1000100],a[1000100],q[1000100],m;
int id[1000100],fi,tl;
int n,d;
int main(){
int i,j=1,k;
n=ra(),m=ra2(),d=ra();
for(i=1;i<=n;i++)a[i]=ra2();
for(i=1;i<=n;i++)pre[i]=pre[i-1]+a[i];
for(i=1;i<=n-d+1;i++)del[i]=pre[i+d-1]-pre[i-1];
int Ans=0;
fi=1,tl=1;
q[tl]=del[1];
for(i=d;i<=n;i++){
while(tl>=fi&&q[tl]<=del[i-d+1])tl--;
q[++tl]=del[i-d+1];
id[tl]=i-d+1;
for(j;j<=i;j++){
while(id[fi]<j)fi++;
long long x=q[fi];
if(pre[i]-pre[j-1]-x<=m){
Ans=max(Ans,i-j+1);
break;
}
}
}
printf("%d\n",Ans);
return 0;
}