如果我們把序列處理成前綴和 (表示為$SUM_{i}$),那麼問題就變成,找出兩個點$a$和$b$ ($a\leq b$),使得$b-a+1\leq K$且$SUM_{b}-SUM_{a-1}$盡量大
因此,我們可以從小到大枚舉$b$,利用單調隊列維護$\min_{k=b-K}^{b-1}SUM_{k}$ (注意$k$的大小寫),然後慢慢更新答案就好了
現在序列是環狀的
我們可以把整個序列再複製一次,接到尾巴
這下就可以把序列當成鏈狀的看待了
時間複雜度:$O(N)$
code:
#include<cstdio> #include<cassert> using namespace std; const int INF=2147483647; struct Deq { int s[200001],l,r; void clear(){l=0,r=-1;} void push_back(const int v){s[++r]=v;} void pop_back(){r--;} void pop_front(){l++;} int size()const{return r-l+1;} int front()const{return s[l];} int back()const{return s[r];} bool empty()const{return r<l;} }DEQ; int N,K,S[200001],SUM[200001]; int main() { // freopen("in.txt","r",stdin); int testcount;scanf("%d",&testcount); while(testcount--) { scanf("%d%d",&N,&K); for(int i=1;i<=N;i++)scanf("%d",&S[i]); for(int i=1;i<=N;i++)S[N+i]=S[i]; for(int i=1;i<=N*2;i++)SUM[i]=SUM[i-1]+S[i]; int ans_sum=-INF,ans_l=-1,ans_r=-1; DEQ.clear(),DEQ.push_back(0); for(int i=1;i<=N*2;i++) { while(DEQ.front()<i-K)DEQ.pop_front(); assert(!DEQ.empty()); const int sum=SUM[i]-SUM[DEQ.front()]; if(sum>ans_sum||(sum==ans_sum&&DEQ.front()<ans_l))ans_sum=sum,ans_l=DEQ.front(),ans_r=i; while(!DEQ.empty()&&SUM[i]<=SUM[DEQ.back()])DEQ.pop_back(); DEQ.push_back(i); } assert(ans_sum!=-INF&&ans_l<N); printf("%d %d %d\n",ans_sum,ans_l+1,(ans_r-1)%N+1); } return 0; }
沒有留言:
張貼留言
歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原
注意:只有此網誌的成員可以留言。