HDU 3415 Max Sum of Max-K-sub-sequence(单调队列)

题目链接:Click here~~

前几天学的单调队列,然后找题目练习,看这道题两天了,终于想通了。

题意:

给你一个循环序列{An},让你找出长度不大于K的连续子序列,使这个子序列和最大。

解题思路:

由于子序列连续,所以和上道题目一样,它的和可以通过两个前缀和作差得到。(即sum[i~j]=sum[j]-sum[i-1](j-i+1<=k))

而对于同一个序列终点来说,起点左边那个元素的前缀和越小,所得到的和越大。

所以,题目又变成了求滚动区间的最小值问题。

#include <stdio.h>
#include <limits.h>
const int M = 100001<<1;
int sum[M],q[M];
int main()
{
    int z,n,k;
    scanf("%d",&z);
    while(z--)
    {
        int start,end,max;
        int head,rear;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&sum[i]);
            sum[i+n] = sum[i];
        }
        for(int i=2;i< n+k;i++)
            sum[i] += sum[i-1];
        head = rear = 0;
        q[head] = 0;
        max = INT_MIN;
        for(int i=1;i< n+k;i++)                 //枚举每个区间终点
        {
            while(head<=rear && sum[i-1]<=sum[ q[rear] ])
                rear--;
            q[++rear] = i-1;

            if(q[head]+1 < i-k+1)               //起点如果大于区间范围,删除队首
                head++;

            if(sum[i] - sum[ q[head] ] > max)
            {
                start = q[head]+1;
                end   = i;
                max   = sum[i] - sum[ q[head] ];
            }
        }
        end = end>n ? end%n : end;
        printf("%d %d %d\n",max,start,end);
    }
    return 0;
}

你可能感兴趣的:(HDU 3415 Max Sum of Max-K-sub-sequence(单调队列))