程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU3415:Max Sum of Max-K-sub-sequence(單調隊列)

HDU3415:Max Sum of Max-K-sub-sequence(單調隊列)

編輯:C++入門知識

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;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved