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

来源:互联网 发布:java多线程抢票 编辑:程序博客网 时间:2024/05/20 22:04

Max Sum of Max-K-sub-sequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4797    Accepted Submission(s): 1752


Problem Description
Given a circle sequence A[1],A[2],A[3]......A[n]. Circle sequence means the left neighbour of A[1] is A[n] , and the right neighbour of A[n] is A[1].
Now your job is to calculate the max sum of a Max-K-sub-sequence. Max-K-sub-sequence means a continuous non-empty sub-sequence which length not exceed K.
 

Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases.
Then T lines follow, each line starts with two integers N , K(1<=N<=100000 , 1<=K<=N), then N integers followed(all the integers are between -1000 and 1000).
 

Output
For each test case, you should output a line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the minimum start position, if still more than one , output the minimum length of them.
 

Sample Input
46 36 -1 2 -6 5 -56 46 -1 2 -6 5 -56 3-1 2 -6 5 -5 66 6-1 -1 -1 -1 -1 -1
 

Sample Output
7 1 37 1 37 6 2-1 1 1
 

Author
shǎ崽@HDU
 

Source
HDOJ Monthly Contest – 2010.06.05
 

Recommend
lcy
 

这里的数列是一个圆,要先预处理一下,变为一条线。

这里多了一点的就是对下标有一点要求,所以我们要维护一个区间长度为k的单调队列。

假设这个区间的长度是 [i,i+k-1];

那么以i+k为结尾的,最大子段和就是 s[i+k]-q[head].(注意head的下标)

注:i+k - [i,i+k-1] <= k 

所以我们可以维护当前的k区间最小,方便求下一个节点往回长度不大于k的子段的最大值。

PS:这里的队列队头要预存一个值为sum=0的节点

题目其他的约束条件就不用考虑了。应为这个算法找到的就是角标最小。长度最小的解。除非有更大值去更新

#include <iostream>#include<stdio.h>#include<string.h>using namespace std;struct node1//单调队列结构{    int val;//存值    int id;//存下标} q[100100];int a[200100],sum[200100];int l,r,head,tail,ans;int n,k;int main(){    int i,t;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&k);        memset(sum,0,sizeof sum);        l=r=0;//必须这么初始化原因见下        head=tail=1;        ans=0xcfcfcfcf;        q[tail].id=0;        q[tail].val=0;        for(i=1;i<=n;i++)        {            scanf("%d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        for(i=n+1;i<=2*n;i++)        {            a[i]=a[i-n];            sum[i]=sum[i-1]+a[i];        }        for(i=1;i<=n+k-1;i++)        {            if(sum[i]-q[head].val>ans)//更新最大和            {                ans=sum[i]-q[head].val;                r=i;                l=q[head].id+1;//从最小值的下一个开始            }            while(tail>=head&&sum[i]<q[tail].val)//把sum[i]入队                  tail--;            q[++tail].val=sum[i];            q[tail].id=i;            if(i>=k)            {                while(q[head].id<i-k+1)//出队不满足范围的元素                    head++;                if(q[head].id>=n)//避免重复                    break;            }        }        if(r>n)            r-=n;        printf("%d %d %d\n",ans,l,r);    }    return 0;}