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;

}

 

你可能感兴趣的:(sequence)