hdu 3415 Max Sum of MaxKsubsequence

  做dp遇到了单调队列优化的问题,所以便又跑来学这东西来了,单调队列,单调栈。

  最近一直在被老师,被同学糗,吼吼。> <

  题意:给定一个长度为n的环形序列,让你从中找出一个k长的子序列,使得这段序列的和是所有k长子序列中和最大的那个,输出和,并输出得到这个和时的起始位置跟终止位置。

  思路:因为还要记录起始位置跟终止位置,所以很显然队列结点还需要记录下标。我们用一个单调减队列来维护到当前下标时,前面sum的最小值,当然还需要head++使得长度控制在k的范围内。循环判断更新最大值,并记录相应下标就可以了。

View Code
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>

using namespace std;

const int maxn=100000+5;

int a[maxn],sum[maxn<<1],head,tail,n,k,st,ed,ans;
struct node
{
    int val;
    int tag;
    node(int v=0,int t=0):val(v),tag(t){}
}q[maxn<<1];

void data_in()
{
    memset(sum,0,sizeof(sum));
    memset(a,0,sizeof(a));
    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];
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&k);
        data_in();
        head=1;tail=1;
        q[tail]=node(0,1);
        st=ed=1;
        ans=sum[1];
        for(int i=2;i<=n+k;i++)
        {
            while(head<=tail&&q[tail].val>sum[i-1]) tail--;
            q[++tail]=node(sum[i-1],i);
            while(head<=tail&&q[head].tag<=i-k) head++;
            int tmp=sum[i]-q[head].val;
            if(tmp>ans)
            {
                ans=tmp;
                st=q[head].tag;
                ed=i;
            }
        }
        if(st>n) st-=n;
        if(ed>n) ed-=n;
        printf("%d %d %d\n",ans,st,ed);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/RainingDays/p/2971783.html