您的位置:首页 > 其它

HDOJ 1024 Max Sum Plus Plus

2017-05-24 19:40 239 查看

Max Sum Plus Plus

TimeLimit: 2000/1000 MS (Java/Others)    Memory Limit:65536/32768 K (Java/Others)

Total Submission(s): 28798    Accepted Submission(s): 10099


Problem Description

Now I think you have got an AC in Ignatius.L's "Max Sum" problem. To be abrave ACMer, we always challenge ourselves to more difficult problems. Now youare 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 afunction 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 jwhich 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 haveto 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 -23

 
 
Sample Output

6

8

 

Hint

 

Huge input, scanf and dynamic programming is recommended.

 

题意 :给出m和由n个整数(可正可负)组成的序列,要求在该序列中找出m个不相交的子序列(边界也不能重合),并使其最大。

思路:定义数组sum[],dp[][],ans[][],其中sum[i]表示序列中前i个数的和(前缀和),dp[i][j]表示序列中前j个数找出i个子序列的最大和,而ans[i][j]表示序列中前j个数找出i个子序列且第j个数必须取的最大和。那么分别写出dp,ans数组的状态转移方程。
对于ans数组,ans[i][j]=max(ans[i][j-1],dp[i-1][j-1])+sum[j]-sum[j-1],其中max函数中的第一个参数的对应的情况是此次加入的第j个数与前一个数连成一段,第二个参数的对应的情况是第j个数自己为一段。
对于dp数组,dp[i][j]=max(dp[i][j-1],ans[i][j]),分别对应于第j个数不加与加的情况。
状态转移方程构建完毕,但这样还不够,观察到题面的n很大,所以建立一个二维数组是不现实的,继续分析可得,每次更新值时,dp[i][j]最多只与它前一个状态dp[i-1][j]有关,故可以把第一维变成两种状态的更迭(0和1),而ans[i][j]状态转移时并没有用到第一维状态,故用一维数组实现即可,具体见代码。

#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<(b);++i)
typedef long long ll;
const int maxn= 1000005;
const int mod = 475;
const ll INF = 0x3f3f3f3f;
const double eps = 1e-6;
#define rush() int T;scanf("%d",&T);while(T--)

int dp[2][maxn];
int ans[maxn];
int sum[maxn];
int m,n;

int main()
{
int x;
while(~scanf("%d%d",&m,&n))
{
mst(dp,0);
sum[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
int k=1;
for(int i=1; i<=m; i++)
{
for(int j=i; j<=n; j++)
{
if(i==j) //前j个数取j段,即所有数都取
dp[k][j]=ans[j]=sum[j]; //另外这个方程对ans数组起到了初始化的作用
else
{
ans[j]=max(dp[1-k][j-1],ans[j-1])+sum[j]-sum[j-1];
dp[k][j]=max(ans[j],dp[k][j-1]);
}
}
k=1-k; //dp数组第一维状态的更迭
}
printf("%d\n",dp[m%2]
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: