HDOJ 1024 Max Sum Plus Plus


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 S
1, 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(i
1, 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(i
x,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][n]);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值