Problem Description
Given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and the right neighbour of A[n] is A[1].
Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuous non-empty sub-sequence which length not exceed K.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases.
Then T lines follow, each line starts with two integers N , K(1<=N<=100000 , 1<=K<=N), then N integers followed(all the integers are between -1000 and 1000).
Output
For each test case, you should output a line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the minimum start position, if still more than one , output the minimum length of them.
Sample Input
4
6 3
6 -1 2 -6 5 -5
6 4
6 -1 2 -6 5 -5
6 3
-1 2 -6 5 -5 6
6 6
-1 -1 -1 -1 -1 -1
Sample Output
7 1 3
7 1 3
7 6 2
-1 1 1
這是我們集訓比賽的一道題,出題人說是什麼DP,坑爹啊,比賽完後一看,單調隊列,DP還做不出來
然後就果斷看了一下單調隊列,之是參考別人的代碼後才寫出來的
單調隊列即保持隊列中的元素單調遞增(或遞減)的這樣一個隊列,可以從兩頭刪除,只能從隊尾插入。單調隊列的具體作用在於,由於保持隊列中的元素滿足單調性,對於上述問題中的每個j,可以用O(1)的時間找到對應的s[i]。(保持隊列中的元素單調增的話,隊首元素便是所要的元素了)。
維護方法:對於每個j,我們插入s[j-1](為什麼不是s[j]? 隊列裡面維護的是區間開始的下標,j是區間結束的下標),插入時從隊尾插入。為了保證隊列的單調性,我們從隊尾開始刪除元素,直到隊尾元素比當前需要插入的元素優(本題中是值比待插入元素小,位置比待插入元素靠前,不過後面這一個條件可以不考慮),就將當前元素插入到隊尾。之所以可以將之前的隊列尾部元素全部刪除,是因為它們已經不可能成為最優的元素了,因為當前要插入的元素位置比它們靠前,值比它們小。我們要找的,是滿足(i>=j-k+1)的i中最小的s[i],位置越大越可能成為後面的j的最優s[i]。
在插入元素後,從隊首開始,將不符合限制條件(i>=j-k+1)的元素全部刪除,此時隊列一定不為空。(因為剛剛插入了一個一定符合條件的元素)
#include <stdio.h> #include <queue> #include <algorithm> #include <string.h> using namespace std; int a[111111]; int sum[211111]; const int INF = 0x3fffffff; int main() { int t,n,m,i,j,k,head,end; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); j = n; sum[0] = 0; for(i = 1; i<=n; i++) { scanf("%d",&a[i]); sum[i] = sum[i-1]+a[i];//將前i項和全部存入sum數組中 } int ans = -INF; for(i = n+1; i<n+k;i++) sum[i] = sum[i-1]+a[i-n]; n = n+k-1; deque<int> Q;//雙向隊列 Q.clear(); for(i = 1; i<=n; i++) { while(!Q.empty() && sum[i-1]<sum[Q.back()])//保持隊列的單調性 Q.pop_back(); while(!Q.empty() && Q.front()<i-k)//超過k的長度則消除隊列前面的元素 Q.pop_front(); Q.push_back(i-1); if(sum[i]-sum[Q.front()]>ans)//記錄,sum[n]-sum[m]所得出的是n-1到m+1之間的和 { ans = sum[i]-sum[Q.front()]; head = Q.front()+1; end = i; } } if(end>j) end%=j; printf("%d %d %d\n",ans,head,end); } return 0; }