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

来源:互联网 发布:网络不行怎么办 编辑:程序博客网 时间:2024/04/30 06:09

题目在此


N个数,围成一个环,求最大子段和,但数的个数不能超过K;


这让我想起了地大比赛的那道题,只不过地大比赛的那道数的个数没有限制。当时Wiking的做法是先把数组扩展一倍,然后按照普通最大子段和的dp方法做,如果发现子段数的个数>=n,那就从这个数开始,往前暴力n个数,求出最大和,作为此处的dp值。


这我也那样做了,TLE了,估计是写的太水了,后来换得单调队列记录下标,用sum[i]存a[1~~i]的和,维护一个单调队列,使队列的首元素最小且代表的值也最小


#include<stdio.h>#include<string.h>#include<deque>#include<algorithm>using namespace std;#define N 100010int tCase,n,k;int a[N],sum[N*2];int Max,s,t;deque<int>q;inline int input(){    int ret=0;    bool IsN=1;    char ch;    ch=getchar();    while(ch<'0'||ch>'9')    {        if(ch=='-') IsN=0;        ch=getchar();    }    while(ch>='0'&&ch<='9')    {        ret=ret*10+ch-'0';        ch=getchar();    }    return IsN?ret:-ret;}int main(){    tCase=input();    while(tCase--)    {        n=input(),k=input();        sum[0]=0;        for(int i=1;i<=n;i++)        {            a[i]=input();            sum[i]=sum[i-1]+a[i];        }        for(int i=n+1;i<=n+k;i++)        {            sum[i]=sum[n]+sum[i-n];        }        Max=-1*N*2*1001;        s=t=1;        while(!q.empty()) q.pop_back();        for(int i=1;i<=n+k;i++)        {            while(!q.empty()&&sum[i-1]<sum[q.back()-1]) q.pop_back();//为什么是这样的呢?单调队列的表示的区间在我们计算和时都用了.但其中有一段负的肯定不行            q.push_back(i);            while(!q.empty()&&i-q.front()+1>k) q.pop_front();            if(Max<sum[i]-sum[q.front()-1])            {                Max=sum[i]-sum[q.front()-1];                s=q.front();                t=i;            }        }        printf("%d %d %d\n",Max,s>n?s-n:s,t>n?t-n:t);    }    return 0;}


原创粉丝点击