HDU 1024 Max Sum Plus Plus求前n个数中的若干个数分为连续的m段的最大和值(解析)

来源:互联网 发布:福建网络干部培训 编辑:程序博客网 时间:2024/05/21 06:03
Max Sum Plus Plus

Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u
 HDU 1024

Description

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be a brave ACMer, we always challenge ourselves to 
more difficult problems. Now you are faced with a more difficult problem.

Given a consecutive number sequence S 1, S 2, S3, S4 ... Sx, ... Sn (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ Sx ≤ 32767). We define a function 
sum(i, j) = Si + ... + Sj (1 ≤ i ≤ j ≤ n).

Now given an integer m (m > 0), your task is to find m pairs of i and j which make sum(i1, j1) + sum(i2, j2) + sum(i3, j3) + ... + sum(im, jm) maximal (ix ≤ iy ≤ jx or ix ≤ jy ≤ jx is not allowed).

But I`m lazy, I don't want to write a special-judge module, so you don't have to output m pairs of i and j, just output the maximal 
summation of sum(ix, jx)(1 ≤ x ≤ m) instead. ^_^
 

Input

Each test case will begin with two integers m and n, followed by n integers S1, S2, S3 ... Sn.
Process to the end of file.
 

Output

Output the maximal summation described above in one line.
 

Sample Input

1 3 1 2 32 6 -1 4 -2 3 -2 3
 

Sample Output

68

Hint

 Huge input, scanf and dynamic programming is recommended. 
 
>>AC代码:
给你m和n,求n个数分为m段的最大和,AC代码如下:#include<stdio.h>#include<algorithm>#include<iostream>using namespace std;#define MAXN 1000000#define INF 0x7fffffffint dp[MAXN+10];int mmax[MAXN+10];int a[MAXN+10];int main(){    int n,m;    int i,j,mmmax;    while(scanf("%d%d",&m,&n)!=EOF)    {        for(i=1;i<=n;i++)        {            scanf("%d",&a[i]);            mmax[i]=0;            dp[i]=0;        }        dp[0]=0;        mmax[0]=0;            for(i=1;i<=m;i++)//i=1,分为一段;i=2分为2段.....        {                mmmax=-INF;                for(j=i;j<=n;j++)                {                    dp[j]=max(dp[j-1]+a[j],mmax[j-1]+a[j]);//以j结尾(总分段包含j)的i段的最大和值                    mmax[j-1]=mmmax;//mmax储存前j-1数(也就是前一个)分为i段的最大和值(不一定包含第j数)                    mmmax=max(mmmax,dp[j]);//即前j个数分为i段的最大和值,这一步被下一次mmax[j-1]储存                }            }          printf("%d\n",mmmax);                }     return 0;   }

________________________________________________________________________________________________________________________
________________________________________________________________华丽分割线——————————————————
看了一下其他人的代码和思路可以对比一下,如下:
大M子段和问题。用d[i][j]表示前j个元素分成i段,且最后一个元素也在其中的状态下能达到的最大和,d[i][j]=max{d[i-1][k]+a[j] | k<j,  d[i][j-1]}。用滚动数组进行空间优化。因为d[i-1][k]需要的是最大值,迭代过程中用变量保存下就好,不用三层循环防止超时。具体细节看代码吧。#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std;typedef long long LL;const int maxn=1000000+10;const LL oo=0x3f3f3f3f3f3f3f3f; int m, n, a[maxn];LL d[2][maxn]; int main(){    while(~scanf("%d%d", &m, &n))    {        for(int i=1; i<=n; i++)            scanf("%d", a+i);        int cur=1, pre=0;        for(int i=1; i<=n; i++)            d[pre][i]=max((LL)a[i], a[i]+d[pre][i-1]);        for(int i=2; i<=m; i++)        {            LL t=d[pre][i-1];            for(int j=i; j<=n; j++)            {                d[cur][j]=t+a[j];                if(j-1>=i)                    d[cur][j]=max(d[cur][j], d[cur][j-1]+a[j]);                t=max(t, d[pre][j]);            }            swap(cur, pre);        }        LL ans=-oo;        for(int i=m; i<=n; i++)            ans=max(ans, d[pre][i]);        printf("%d\n", ans);    }    return 0;}


但实际这个代码会超时,不过这个代码的算法思想可以借鉴一下,还是挺不错的!

0 0