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
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 ≤ j x 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
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 ≤ j x 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.
Process to the end of file.
Output
Output the maximal summation described above in one line.
Sample Input
1 3 1 2 3 2 6 -1 4 -2 3 -2 3
Sample Output
6 8
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 0x7fffffff int 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; }
但实际这个代码会超时,不过这个代码的算法思想可以借鉴一下,还是挺不错的!