hdu 3415 Max Sum of Max-K-sub-sequence

hdu 3415 Max Sum of Max-K-sub-sequence
//hdu 3415 Max Sum of Max-K-sub-sequence
//单调队列
//题意是说给出一串数字,形成环,求长度小于等于k的子串中的最大子串和
//思路:用数组num[i]保存前i个数的和,由于 1<=K<=N,所欲数组继续延伸到2n个元素
//就可以忽视环。让后维护一个单调队列,使之保存 i-k到 i-1之间最小 子串和,
//从而,num[i] - que[head] 就是 i-k 到 i 之间的最大子串和

#include <stdio.h>
#include <string.h>

#define N 100005
#define INF 1<<30

int num[N*2], que[N*2];


int main()
{
    int n_case;
    scanf("%d", &n_case);
    while(n_case--)
    {
        int n, k;
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d", &num[i]);
            num[n+i] = num[i];
        }
        n *= 2; // 1<=K<=N, so 2*n is enough
        for(int i = 2; i <= n; ++i)
            num[i] += num[i-1];

        int ans = -INF, left = 0, right = 0;
        int head = 1, tail = 0;
        for(int i = 1; i <= n; ++i) //求 i 之前满足条件的最大子串和
        {
            while(tail >= head && num[i-1] < num[ que[tail] ])//若第i-1 个数小于
                tail--;     //队尾的数则舍去队尾,因为第i-1个数比队尾新 而且比它小
            que[++tail] = i-1;
            while(que[head] < i-k)
                head++;
            if(ans < num[i] - num[ que[head] ])
            {
                ans = num[i] - num[ que[head] ];
//                if(num[ que[head] ] < 0)  //不需要这个判断,因为单调队列讨论的是
                    left = que[head] + 1;   //从num[0]开始的,而这个值为0;若这个大于0
//                else          //则可能是因为num[que[head]]这段和已过期了,如-1 1 2 3 4 5
//                    left = que[head]; //想一想就知道了,我也说不清
                right = que[tail];
            }
        }
        right = right > n/2 ? right - n/2 : right;
        printf("%d %d %d\n", ans, left, right+1);
    }
    return 0;
}

 

posted @ 2012-07-09 15:11  gabo  阅读(170)  评论(0编辑  收藏  举报