Max Sum Plus Plus
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 44532 Accepted Submission(s): 16138
Problem 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 S1, S2, 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 3
2 6 -1 4 -2 3 -2 3
Sample Output
6
8
Hint
Huge input, scanf and dynamic programming is recommended.
题意:给你由 N 个整数组成的序列,找出 M 段连续且不重叠的子序列,使得这 M 段子序列的和最大。
思路: 用 dp[i][j] 表示将前 j 个数分成 i 组的情况,因此对于当前的第 j 个数使其满足 i 个组的情况有如下两种:
- dp[ i ][ j - 1 ] + a[ j ] // 将第 j 个数加入第 i 组 (ps : 读入的数据都放在 a[ ] 数组中 )
- max ( dp[ i - 1 ][ k ] ) + a[ j ] ( 1 <= k < j ) // 因为此时第 j 个数单独组成第 i 组,所以要只要取 i - 1 组所有组成情况 的最大值 (与第 j 个数无瓜)
想法是很好的,但是还需要优化,因为 N 的最大值为 1,000,000。且 M 的范围未知,所有很容易爆内存。因此考虑滚动数组。
具体优化如下:
- 使用 Max[ j ] 数组代表 用 j 个数组成 i - 1 组 的最大值,相当于 Max[ j ] = max ( dp[ i - 1 ][ k ] ) // ( 1 <= k <= j )
- 使用 dp[ j ] 数组代表 用 j 个数组成 i 组 的最大值
因此动态转移方程就可以表示为 dp[ j ] = max( dp[ j - 1 ] + a[ j ] , Max[ j - 1] + a[ j ] )
代码如下:
//#include <bits/stdc++.h>
#include <map>
//#include <tr1/unordered_map>
#include<limits>
#include <float.h>
#include <list>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int lowbit(int x){ return x & (-x); }
inline int read(){int X = 0, w = 0; char ch = 0;while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();return w ? -X : X;}
inline int gcd(int a, int b){ return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define db double
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
const double pi = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e6 + 10;
const int maxp = 1e3 + 10;
const LL INF = 0x3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int mod = 20090717;
int m, n, maxx;
int a[maxn];
int Max[maxn]; // Max[j] = max(dp[i-1][k]) (1<=k<=j), 代表用j个数组成i-1组的最大值
int dp[maxn]; // 代表用 j 个数组成 i 组的最大值
int main(){
while (~scanf("%d%d", &m, &n)){
Mem(dp, 0); //初始化数据
Mem(Max, 0);
For (i, 1, n)
a[i] = read();
For (i, 1, m){
maxx = -inf;
For (j, i, n){ // 至少 i 个数才能组成 i 组
dp[j] = max(dp[j - 1], Max[j - 1]) + a[j];
Max[j - 1] = maxx; //此时的 Max[ ] 前一部分已经不断跟新为组成 i 组的最大值,后面一部分仍是
//组成 i - 1 组的,因此在此只能延迟跟新, 若在此直接跟新 Max[ j ], 下一
//个数(j + 1)使用的Max[(j + 1) - 1] 将是组成 i 组的最大值,就造成错误了
maxx = max(maxx, dp[j]);
}
}
Pri(maxx);
}
return 0;
}