题面
分析
一道较为简单的单调队列题目
思路和上一道题很像,就是枚举右端点,然后找到满足条件的“最左”的左端点
怎么找呢,我们发现随着右端点的右移,其实左端点也在不断地右移,那么就是左端点单调不减
然后我们就可以想到单调队列来维护了
队列当中维护的信息是什么呢...
左端点位置?不是。
因为这样维护的话我们每次还要在当前区间当中找到最大的长度为(d)的区间,很麻烦
所以我们直接维护这个长度为(d)的区间的和的最大值,以及这个区间的左端点即可(就是说队列里存的是这个区间和的最大值对应区间的位置,而且在这个过程中,我们顺带记一下左端点(st)的位置)
然后总复杂度就是(O(n))的,具体细节看代码
代码
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
const int N=2e6+5;
ll n,p,d,hh,tt=-1,que[N],a[N],pre[N],val[N],st=1,ans;
int main(){
read(n),read(p),read(d);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
for(int i=d;i<=n;i++) val[i]=pre[i]-pre[i-d];
que[++tt]=d,ans=d;
for(int i=d+1;i<=n;i++){
while(hh<=tt&&val[i]>val[que[tt]]) tt--;//维护最大的长度为$d$的区间
que[++tt]=i;
while(hh<=tt&&pre[i]-pre[st-1]-val[que[hh]]>p) st++;
while(hh<=tt&&que[hh]-d+1<st) hh++;//如果本身这个最大值已经不在当前$st-i$的区间内,直接弹出
ans=max(ans,i-st+1);
}
write(ans);
return 0;
}