很久以前不求甚解的看了一下,然后就没有管了,今天牛客的多校又考到这个点了,遗憾由于根本没有理解单调队列所以没有往这个方向想。
单调队列是一个双端队列,他从头到尾,首先维护了下标的递增,其次根据需要维护了值的递增或递减。
比较经典的就是滑动窗口了。
给定一个大小为k的框,可以框住k个连续的数字,现在问你框不超过k个连续数字使得这些元素和最大。
预处理前缀和sum[],那么我们应该使得区间左端点尽量靠前,且前缀和较小,右端点尽量靠后,且前缀和较大。
于是单调队列就维护了一个下标递增,且s也递增的东西。
对于i=1->n
首先将队头超出位置的元素弹出。
然后判断答案
接下来将队尾比sum[i]大的元素弹出,然后将i加入队尾。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
int a[maxn];
int q[maxn];
const int inf=0x3f3f3f3f;
int main(){
int n,k;
int l=1,r=1;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
a[i]+=a[i-1];
}
q[1]=0;
int res=-inf;
for(int i=1;i<=n;++i){
while(l<=r&&q[l]<i-k) ++l;
res=max(res,a[i]-a[q[l]]);
while(l<=r&&a[q[r]]>=a[i]) --r;
q[++r]=i;
}
printf("%d\n",res);
return 0;
}