看到这个数据规模,大概只能是O(n)了,选择一段忽略,很明显应该是选择一段内的最大值,考虑到单调队列。
这道题需要用到双指针的思想。通过left和right两个指针固定一段数,其中被覆盖的肯定是最大的一段m,通过单调队列维护覆盖掉那一段的最大值。每次right右移需要保证left要取到最大,于是加上right节点后判断 区间和 - 单调队列维护的最大值 是否大于p,若超出p左移left指针。保证left取到最小值,即满足小于等于p即停下,记录区间长度然后继续左移left。
这里单调队列的维护肯定以每次新加入的right为准,然后发现维护的一段m的左端点已不在[left,right]区间内,则直接舍弃。由于以left作为判定条件,所以left右移时需要维护单调队列,这个一定要记住。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2000005;
int n,ans,m;
int a[maxn],q[maxn];
long long limit,sum[maxn];
long long read()
{
long long x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
return x;
}
int main()
{
n=read();limit=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read(),sum[i]=1LL*a[i]+sum[i-1];
int right=1,left=1,head=1,rear=0;
long long temp=a[1];
q[++rear]=1;
while(right<=n)
{
while(true)
{
while(head<=rear&&right>m&&q[head]-m+1<left)head++;
if(right>m&&temp-sum[q[head]]+sum[q[head]-m]>limit)
temp-=a[left++];
else break;
}
ans=max(ans,right-left+1);
temp+=a[++right];
while(head<=rear&&sum[right]-sum[right-m]>sum[q[rear]]-sum[q[rear]-m])
rear--;
q[++rear]=right;
}
printf("%d",ans);
}