Max Sum Plus Plus
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24256 Accepted Submission(s): 8313
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 S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (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(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y≤ 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(i x, j x)(1 ≤ x ≤ m) instead. ^_^
Given a consecutive number sequence S 1, S 2, S 3, S 4 ... S x, ... S n (1 ≤ x ≤ n ≤ 1,000,000, -32768 ≤ S x ≤ 32767). We define a function sum(i, j) = S i + ... + S j (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(i 1, j 1) + sum(i 2, j 2) + sum(i 3, j 3) + ... + sum(i m, j m) maximal (i x ≤ i y ≤ j x or i x ≤ j y≤ 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(i x, j x)(1 ≤ x ≤ m) instead. ^_^
Input
Each test case will begin with two integers m and n, followed by n integers S
1, S
2, S
3 ... S
n.
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 8HintHuge input, scanf and dynamic programming is recommended.
Author
JGShining(极光炫影)
思路:用dp[i][j]表示将j个数字分成i段,并且最后一段以numb[j]结尾的最大和,那么dp[i][j]的来源情况只有两种:
1.将前j-1个数分成i段,然后把这个数直接接在最后一段,那么dp[i][j] = dp[i][j-1] + numb[j].
2.将前j-1个数分成i-1段,然后再将第j个数变成独立的一段 那么dp[i][j] = max(dp[i-1][k])(i-1<=k<j)
综上可以得到转移方程:dp[i][j] = max( dp[i][j-1] + numb[j], max(dp[i-1][k])(i-1<=k<j) )
但是n的范围是1e6,显然开二维数组是不行的,需要优化一下。
优化:发现dp[i][j] 之和dp[i][j-1]以及dp[i-1][k]有关,我们可以用一个一维数组,每次滚动记录dp[i][j].
但是这样的话,寻找max(dp[i-1][k])还需要遍历一遍,显然是不合理的,所以我们再开一个数组pre[j]记录max(dp[i-1][k])(i-1<=k<j).
这样我们便可以每次直接读取这个值即可。
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <string>
#if defined(_MSC_VER) || __cplusplus > 199711L
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) __typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define fur(i,a,b) for(int i=(a);i<=(b);i++)
#define furr(i,a,b) for(int i=(a);i>=(b);i--)
#define cl(a) memset((a),0,sizeof(a))
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define sc(x) scanf("%d",&x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const int mod=1000000007;
const double pi=acos(-1);
inline void gn(long long&x){
int sg=1;char c;while(((c=getchar())<'0'||c>'9')&&c!='-');c=='-'?(sg=-1,x=0):(x=c-'0');
while((c=getchar())>='0'&&c<='9')x=x*10+c-'0';x*=sg;
}
inline void gn(int&x){long long t;gn(t);x=t;}
inline void gn(unsigned long long&x){long long t;gn(t);x=t;}
inline void gn(double&x){double t;scanf("%lf",&t);x=t;}
inline void gn(long double&x){double t;scanf("%lf",&t);x=t;}
int gcd(int a,int b){return a? gcd(b%a,a):b;}
ll powmod(ll a,ll x,ll mod){ll t=1ll;while(x){if(x&1)t=t*a%mod;a=a*a%mod;x>>=1;}return t;}
// (づ°ω°)づe★
int numb[1000005];
int dp[1000005];
int pre[1000005];
void init(){
cl(dp);
cl(pre);
}
int n,m;
int main(){
int tmp;
while(~scanf("%d %d",&m,&n)){
init();
fur(i,1,n)gn(numb[i]);
fur(i,1,m){
tmp = -inf;
fur(j,i,n){
dp[j] = max(dp[j-1],pre[j-1]) + numb[j];
pre[j-1] = tmp; //因为计算到dp[j]的时候 ,需要用到pre[j-1]
tmp = max(dp[j],tmp); //所以我们不能在获得dp[j-1]的时候立刻更新pre[j-1]
} //而是先临时保存一下这个值
} //当计算完dp[j]以后再修改dp[j-1];
printf("%d\n",tmp); //因为最大的值不一定是以numb[n]结尾的
} //所以不能输出 dp[n] 而是应该输出dn[i]里面最大的那个
return 0;
}