HDU1024_Max Sum Plus Plus【滚动数组】

Max Sum Plus Plus

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

Total Submission(s): 17436    Accepted Submission(s): 5731

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.

Author

JGShining(极光炫影)

题目大意:给你两个数M和N,之后是N个数,从这N个数找到M个子段,

求M个子段的最大和

思路:一开始不懂怎么找状态转移方程。参考别人博客才明白。

.设dp[i][j] 为将前 j 个数字分成 i 段的最大和。num[j]为当前数字

那么转移方程为 dp[i][j] = max(dp[i][j-1]+num[j],dp[i-1][k]+num[j]) (i-1<=k<=j-1)

也可以视为 dp[i][j] = max(dp[i][j-1]+num[j],max(dp[i-1][i-1],dp[i-1][i],…,dp[i-1][j-1])
)

//注:max(dp[i-1][i-1],dp[i-1][i],…,dp[i-1][j-1]) 就是dp[i-1][j-1]

意思是:前 j 个数字分成 i 段的最大和有两个决策。

1、将当前第j个数字并入第i段,与第j-1个数字所在的一段并为一段的最大和。

2、将当前第j个数字作为第i段,而第k个数字所在的一段为第i-1段,区间(k+1,j-1)的数字

不再选则的最大和。

取这两个决策中最大值。

本题还有一个难点在于将二维转为一位数组。考虑到第i行的状态由第i-1行和第i行递推过来,

所以可以利用滚动数组将二维压缩为一维数组,过程有点不太理解,留到以后慢慢想。

参考博文:http://blog.csdn.net/acm_davidcn/article/details/5887401

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int dp[1000010];
int maxn[1000010];
int num[1000010];
int main()
{
    int M,N;
    while(~scanf("%d%d",&M,&N))
    {
        dp[0] = maxn[0] = 0;
        for(int i = 1; i <= N; i++)
        {
            scanf("%d",&num[i]);
            dp[i] = maxn[i] = 0;
        }
        int MAXN;
        for(int i = 1; i <= M; i++)//分为i段
        {
            MAXN = -0xffffff0;
            for(int j = i; j <= N; j++)//第j个数字
            {
                dp[j] = max(dp[j-1]+num[j],maxn[j-1]+num[j]);
                maxn[j-1] = MAXN;
                MAXN = max(MAXN,dp[j]);
            }
        }
        printf("%d\n",MAXN);
    }

    return 0;
}
时间: 2024-10-09 21:18:34

HDU1024_Max Sum Plus Plus【滚动数组】的相关文章

HDU - 1024 Max Sum Plus Plus 滚动数组优化

给定n个数字,求其中m段的最大值(段与段之间不用连续,但是一段中要连续) 例如:2 5 1 -2 2 3 -1五个数字中选2个,选择1和2 3这两段. dp[i][j]从前j个数字中选择i段,然后根据第j个数字是否独立成一段,可以写出 状态转移方程:dp[i][j]=max(dp[i][j-1]+num[j],max(dp[i-1][k])+num[j]) 这里的max(dp[i-1][k])代表的拥有i-1段时的最大值,然后再加上num[j]独立成的一段. 但是题目中没有给出m的取值范围,有可

HDU 1024 Max Sum Plus Plus --- dp+滚动数组

HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值,其中第i个子序列包括a[j], 则max(dp[m][k]),m<=k<=n 即为所求的结果 <2>初始状态: dp[i][0] = 0, dp[0][j] = 0; <3>状态转移: 决策:a[j]自己成为一个子段,还是接在前面一个子段的后面 方程: a[j]直接接在前面

【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus

A - Max Sum Plus Plus 1 https://vjudge.net/contest/68966#problem/A 2 3 http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127085.html 4 5 /* 6 状态dp[i][j]有前j个数,组成i组的和的最大值.决策: 7 第j个数,是在第包含在第i组里面,还是自己独立成组. 8 方程 dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-

HDU 1024 Max Sum Plus Plus (DP&#183;滚动数组)

题意  从n个数的数组中选出不相交的m段  求被选数的和的最大值 Max Sum 的升级版  不只是要选一段连续的了  而是选m段  思想还是类似  依旧dp 状态和状态转移方程不是很难想  在 Max Sum 这个问题中 dp[i] 表示的是以第i个数结尾的一段的 Max Sum  由于这里还有一个多少段的状态  于是这里令 dp[i][j] 表示在前 i 个数中选取 j 组  且第 i 个数在最后一组中的 Max Sum Plus Plus 那么现在对于第i个数有两种决策 1,  第 i 个

HDU - 1024 Max Sum Plus Plus(dp+滚动数组优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 题意:给定n个数字,求其中m段的最大值(段与段之间不用连续,但是一段中要连续) 例如:2 5 1 -2 2 3 -1五个数字中选2个,选择1和2 3这两段. 题解:dp[i][j]从前j个数字中选择i段,然后根据第j个数字是否独立成一段,可以写出 状态转移方程:dp[i][j]=max(dp[i][j-1]+num[j],max(dp[i-1][k])+num[j]) 这里的max(dp[i-

hdu 1864 实数离散化+动态规划+滚动数组

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <stack> #include <set> #include <map> #include <vector> using namespace st

poj3624 01背包入门 dp+滚动数组

poj3624 01背包 dp+滚动数组 Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 25458   Accepted: 11455 Description Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the bes

Codeforces 712 D. Memory and Scores (DP+滚动数组+前缀和优化)

题目链接:http://codeforces.com/contest/712/problem/D A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A比B大的情况有多少种. dpA[i][j]表示第i轮获得j分的情况数.因为第i轮只和第i-1轮有关,所以这里i用滚动数组优化. 要是普通做法3个for就会超时,所以要用前缀和优化,dpA[i][j]可以由一段连续的dp[i - 1][x]转移过来,所以用sumA数组存取dp[i - 1][x]的前缀

大数数组中滚动数组的应用

对于数组中的大数加法 为了节省内存 可以考虑使用滚动数组杭电1250 Problem Description A Fibonacci sequence is calculated by adding the previous two members the sequence, with the first two members being both 1.F(1) = 1, F(2) = 1, F(3) = 1,F(4) = 1, F(n>4) = F(n - 1) + F(n-2) + F(n