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;
}
posted @ 2013-02-27 16:30  kedebug  阅读(223)  评论(0编辑  收藏  举报