如何学过单调队列就能发现是裸题,因为题目求的是最大子序和,而我们发现就是跟前缀和相关,也就是说对每个点找到最小前缀和
这里因为是环,所以破环成链,但是这样会导致结束坐标可能超过n,只要%n即可,开始坐标不可能超过n,因为超过n跟从头开始是一样的,所以不会更新到
#include<iostream> #include<queue> #include<map> #include<vector> #include<cstdio> #include<algorithm> #include<stack> #include<cstring> using namespace std; typedef long long ll; const int N=2e6+7; const int inf=0x3f3f3f3f; int a[N]; int q[N]; int s[N]; int main(){ int t; cin>>t; while(t--){ int n,k; cin>>n>>k; int i,j; memset(s,0,sizeof s); for(i=1;i<=n;i++){ scanf("%d",&a[i]); s[i]=s[i+n]=a[i]; } for(i=1;i<=2*n;i++) s[i]+=s[i-1]; int hh=0; int tt=0; q[0]=0; int res=-0x3f3f3f3f; int pos=0; int ed=0; for(i=1;i<=2*n;i++){ while(hh<=tt&&q[hh]<i-k) hh++; if(s[i]-s[q[hh]]>res){ res=s[i]-s[q[hh]]; pos=q[hh]+1; ed=i; } else if(s[i]-s[q[hh]]==res){ if(pos>q[hh]+1){ pos=q[hh]+1; ed=i; } else if(pos==q[hh]+1){ if(i<ed) ed=i; } } while(hh<=tt&&s[q[tt]]>=s[i]) tt--; q[++tt]=i; } if(ed>n) ed-=n; cout<<res<<" "<<pos<<" "<<ed<<endl; } }