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

题目给出的是一个环状的序列,所以可以在序列后面复制前k个数字。如果用sum[i]来表示复制过后的

序列的前i个数的和,那么任意一个子序列 [i..j]的和就等于s[j]-s[i-1]。对于每一个j,用s[j]减去

最小的一个s[i](i>=j-k+1)就可以得到以j为终点长度不大于k的和最大的序列了。将原问题转化为这样

一个问题后,就可以用单调队列解决了。单调队列确实是一种很实用的结构,本题中保持单调递增,队

首元素就是我们需要的那个最小元素,保证待插入的j-1位置对应的sum值要大于队尾元素。

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <queue>

#include <algorithm>

using namespace std;



const int MAXN = 100010;

const int INF = 0x3fffffff;

int a[MAXN], sum[MAXN << 1];

int N, K, n, st, end, ans;



void Read()

{

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

    sum[0] = 0;

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

    {

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

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

    }

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

    {

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

    }

    n = N + K - 1;

}



void cal()

{

    deque<int> q;

    q.clear();

    ans = -INF;

    for(int j = 1; j <= n; j ++)

    {

        while(!q.empty() && sum[j - 1] < sum[q.back()]) //队尾元素大于

        {

            q.pop_back();

        }

        while(!q.empty() && q.front() < j - K)

        {

            q.pop_front();

        }

        q.push_back(j - 1); //插入j - 1

        if(sum[j] - sum[q.front()] > ans)

        {

            ans = sum[j] - sum[q.front()];

            st = q.front() + 1;

            end = j;

        }

    }

}



int main()

{

    int T;

    scanf("%d", &T);

    while(T --)

    {

        Read();

        cal();

        if(end > N) end %= N;

        printf("%d %d %d\n", ans, st, end);

    }

    return 0;

}

 

 

你可能感兴趣的:(sequence)