【DP+单调队列】 hdu3415 Max Sum of Max-K-sub-sequence

Max Sum of Max-K-sub-sequence

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3415

题意:一个长度为n包含正负整数的数环,即第1个的左边是第n个。从中选一个不超过k的序列,使得序列和最大,最大值相同选开始点最小的,开始点相同选长度最小的。

题解:不难看出动态方程为dp[i]=max{sum[i]-sum[j]}(i-k<j<i) ,dp[i]表示以i结尾的最大值,sum表示从1到i的序列和,枚举的话要0(n^2),明显要超时,这时可以使用单调队列维护一个非递减队列,因为对于确定的i,要使和最大就得使sum[j]最小,而单调队列的队头就是能选的j中sum[j]最小的。

代码:

#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 100005
#define inf 0xfffff
int summ[MAX<<1];//summ[i]代表1到i的和
int value[MAX<<1];//value[i]代表第i个值
int q[MAX<<1];//模拟队列,存放选取位置的下标
int front,back;//队列头尾
int main()
{
    int t,n,m,k,cnt;
    scanf("%d",&t);
    for(;t--;)
    {
        summ[0]=0;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",value+i);
            summ[i]=value[i]+summ[i-1];
        }
        for(int i=n+1;i<=n+k;++i) summ[i]=summ[i-1]+value[i-n];
        m=n+k-1;
        front=back=1;
        int ans=-inf,st,en;
        //dp[i]=max{summ[i]-summ[j]}(i-k<j<i) dp[i]为以第i个结尾的最大值
        //对于每个i要使最大值最大,就得选summ[j]最小的
        for(int i=1;i<=m;++i)
        {
            for(;front<back&&summ[i-1]<summ[q[back-1]];--back);//维护单调非递减序列
            q[back++]=i-1;
            for(;front<back&&i-q[front]>k;++front);//将队头超出范围的舍弃
            if(summ[i]-summ[q[front]]>ans)
            {
                ans=summ[i]-summ[q[front]];
                st=q[front]+1;
                en=i;
            }
        }
        if(en>n) en%=n;
        printf("%d %d %d\n",ans,st,en);
    }
    return 0;
}

来源: http://blog.csdn.net/acm_ted/article/details/7909178

你可能感兴趣的:(【DP+单调队列】 hdu3415 Max Sum of Max-K-sub-sequence)