求长度不大于(k)的最大子段和
求前缀和,枚举答案的右端点,对于每个右端点,求以该点为右端点,长度为(k)的区间的最小值
用单调队列维护值单调递增的下标,对于每个右端点,若队首元素与当前位置的距离不满足要求,则出队,否则记录答案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
int a[maxn<<1],q[maxn<<1];
int main()
{
int _,n,k;
for(scanf("%d",&_);_;_--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)a[i+n]=a[i];
n<<=1;
for(int i=1;i<=n;i++)a[i]+=a[i-1];
int l=0,r=2,ans=a[1],lans=1,rans=1;
q[0]=0;
q[1]=1;
for(int i=2;i<=n;i++){
while(l<r&&q[l]+k<i)l++;
if(a[i]-a[q[l]]>ans){
ans=a[i]-a[q[l]];
lans=q[l]+1;
rans=i;
}
while(l<r&&a[i]<a[q[r-1]])r--;
q[r++]=i;
}
if(lans>n/2)lans-=n/2;
if(rans>n/2)rans-=n/2;
printf("%d %d %d
",ans,lans,rans);
}
return 0;
}