zoukankan      html  css  js  c++  java
  • 【题解】最大 M 子段和 Max Sum Plus Plus [Hdu1024] [51nod1052]

    【题解】最大 M 子段和 Max Sum Plus Plus [Hdu1024] [51nod1052]

    传送门:最大 (M) 子段和 (Max) (Sum) (Plus) (Plus) ([Hdu1024]) ([51nod1052])

    【题目描述】

    给出一个长度为 (N) 的序列 ,将这 (N) 个数划分为互不相交的 (M) 个子段,并使得 (M) 个子段的和最大。

    【样例】

    样例输入:
    7 2
    -2
    11
    -4
    13
    -5
    6
    -2
    
    样例输出:
    26
    

    【数据范围】

    (100\%) (1 leqslant N leqslant 10^6)


    【分析】

    (51nod) 里面这道题的数据水出了一种极其诡异的境界,首先是它题目里瞎扯的一个特判没毛用,其次,我尝试了不下 (10) 种错误写法(包括不同题意所造成的不同写法),居然全对 (...)

    (dp[i][j]) 表示使用前 (j) 个数划分了 (i) 段的最大和。
    由于所选段不一定要连续,所以 (dp[i][j]=dp[i][j-1]),即第 (i) 段不选 (a[j]) 的情况。

    如果要选 (a[j]) ,那么应该是从 (a[j]) 往前选出连续的一段 ([k+1,j]) 作为第 (i) 段,即 (dp[i][j]=max{dp[i-1][k]+S[j]-S[k]]}),其中 (k in[i-1,j-1],) 为了保证这之后剩下的数可以足够选完 (m) 段,需要满足 (i-j geqslant m-n)(j in [i,n-m+i])(S[i])(a[i]) 的前缀和 。

    开一个滚动数组 (f) 优化掉第一维,就成了酱紫: (dp[j]=egin{cases} max_{k=i-1}^{j-1}{f[k]-S[k]]}+S[j] & j=i\max{dp[j-1],{max_{k=i-1}^{j-1}{f[k]-S[k]]}+S[j]}} & j>i end{cases})

    对于上面 (j=i) 的情况,实际操作时,可以特判,也可以直接 (dp[i-1]=-inf)
    后面那一大堆求最大值的表达式可以直接用一个变量 (maxs) 来保存,初始值为 (f[i-1]-S[i-1]),每求完一个 (dp[j]),就让其与 (f[j]-S[j]) 取个最大值,下一次 (dp[j+1]) 要使用 (maxs) 时,其维护的区间信息恰好为 ([i-1,(j+1)-1])


    【Code】

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #define LL long long
    #define Re register LL
    using namespace std;
    const int N=1e6+3;
    LL n,m,tmp,ans,maxs,S[N],f[N],dp[N];
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    int main(){
        while(scanf("%lld%lld",&m,&n)!=EOF){
            for(Re i=1;i<=n;++i)in(S[i]),tmp+=(S[i]>0),S[i]+=S[i-1];
            memset(dp,0,sizeof(dp));
            memset(f,0,sizeof(f));
            for(Re i=1;i<=m;++i){
          	    for(Re j=1;j<=n;++j)f[j]=dp[j];
          	    maxs=f[i-1]-S[i-1];
          	    dp[i-1]=-1e18;
          	    for(Re j=i;j<=n-m+i;++j){
                    dp[j]=max(dp[j-1],maxs+S[j]);
                    maxs=max(maxs,f[j]-S[j]);
          	    }
            }
            printf("%lld
    ",dp[n]);
        }
    }
    
  • 相关阅读:
    总有一天你会爱上我
    你已把我的心带走
    创业提示】创业不能以赚多少钱为目标!
    创业测试:看看你身上成功的潜质
    迁芸(名字作诗)
    请你陪我一程
    智力型企业领导艺术
    方学萍(帮别人名字作诗)
    创业者身上一定要存在的几点修为
    以小博大:小本成功创业经验谈
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/11350953.html
Copyright © 2011-2022 走看看