HDOJ 3415 Max Sum of Max-K-sub-sequence(单调队列变型)

题意:

给定一个环形数组,求数组中连续长度不超过 K 的最大子段和。

思路:

1. 题目中给定的是环形数组,其实可以在数组尾部复制一份原数据,于是把问题规模扩大到了 2 * N,但是方便了解题。

2. 对数据在加以转换:sum[i] 表示 1~i 数组元素的和,由于题目中给定了数据范围,保证了 int 不会溢出。

3. 单调队列里面的数据表示 x~x+k 范围内 sum[] 的最小值。于是 sum[x+k+1] - sum[deq[s]] 即是以 x+k+1 为结尾的子序列最大和。

 

#include <iostream>

#include <algorithm>

using namespace std;



const int MAXN = 100010;

const int INFS = 0x7fffffff;



int sum[MAXN * 2], deq[MAXN * 2];



int main()

{

    int cases;

    scanf("%d", &cases);

    while (cases--)

    {

        int N, K;

        scanf("%d %d", &N, &K);



        sum[0] = 0;

        for (int i = 1; i <= N; ++i)

        {

            scanf("%d", &sum[i]);

            sum[i+N] = sum[i];

        }



        for (int i = 1; i <= 2 * N; ++i)

            sum[i] += sum[i-1];



        int s = 0, e = -1;

        int ans = -INFS, beg = 0, end = 0;



        for (int i = 0; i < 2 * N; ++i)

        {

            if (i >= K && sum[i-K] == sum[deq[s]])

                ++s;



            while (s <= e && sum[i] < sum[deq[e]])

                --e;



            deq[++e] = i;



            if (sum[i+1] - sum[deq[s]] > ans)

            {

                ans = sum[i+1] - sum[deq[s]];

                beg = deq[s] + 1, end = i + 1;

            }

        }

        printf("%d %d %d\n", ans, (beg - 1) % N + 1, (end - 1) % N + 1);

    }

    return 0;

}

你可能感兴趣的:(sequence)