IT民工
加油!

题目给出的是一个环状的序列,所以可以在序列后面复制前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;
}

 

 

posted on 2012-09-12 09:56  找回失去的  阅读(234)  评论(0)    收藏  举报