hdu 1024 Max Sum Plus Plus(DP->k段连续区间的最大和)
2017-11-08 11:55
465 查看
Max Sum Plus Plus
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit Status
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(im, 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.
Output
Output the maximal summation described above in one line.
Sample Input
Sample Output
Hint
Huge input, scanf and dynamic programming is recommended.
本题的大致意思为给定一个数组,求其分成m个不相交子段和最大值的问题。
设Num为给定数组,n为数组中的元素总数,Status[i][j]表示前i个数在选取第i个数的前提下分成j段的最大值,其中1<=j<=i<=n && j<=m,状态转移方程为:
Status[i][j]=Max(Status[i-1][j]+Num[i],Max(Status[0][j-1]~Status[i-1][j-1])+Num[i])
乍看一下这个方程挺吓人的,因为题中n的限定范围为1~1,000,000而m得限定范围没有给出,m只要稍微大一点就会爆内存。但仔细分析后就会发现Status[i][j]的求解只和Status[*][j]与Status[*][j-1]有关所以本题只需要两个一维数组即可搞定状态转移。
在进行更进一步的分析还会发现其实Max(Status[0][j-1]~Status[i-1][j-1])根本不需要单独求取。在求取now_Status(保存本次状态的数组)的过程中即可对pre_Status(保存前一次状态的数组)进行同步更新。
状态dp[i][j]
有前j个数,组成i组的和的最大值。
决策: 第j个数,是在第包含在第i组里面,还是自己独立成组。
方程 dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-1][k] ) + a[j] ) 0<k<j
空间复杂度,m未知,n<=1000000, 继续滚动数组。
时间复杂度 n^3. n<=1000000. 显然会超时,继续优化。
max( dp[i-1][k] ) 就是上一组 0....j-1 的最大值。我们可以在每次计算dp[i][j]的时候记录下前j个
的最大值 用数组保存下来 下次计算的时候可以用,这样时间复杂度为 n^2.
这道题是一段连续区间最大和的升级版,主要思想就是把当前段的最优值记忆下来,最优值为k段最优并上当前值
或k-1段的最优值加上当前值。。。模拟一下一组数据就能体会
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1000000+11;
const int inf = -0x3f3f3f3f;
int dp
, dp1
, v
;
int main()
{
int m, n;
while(scanf("%d %d", &m, &n)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(dp1,0,sizeof(dp1));
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
int flag;
for(int k=1;k<=m;k++)
{
flag=inf;
for(int i=k;i<=n;i++)
{
dp1[i]=max(dp1[i-1]+v[i],dp[i-1]+v[i]);
dp[i-1]=flag;
flag=max(flag,dp1[i]);
}
}
printf("%d\n",flag);
}
return 0;
}
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
Submit Status
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(im, 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.
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.
本题的大致意思为给定一个数组,求其分成m个不相交子段和最大值的问题。
设Num为给定数组,n为数组中的元素总数,Status[i][j]表示前i个数在选取第i个数的前提下分成j段的最大值,其中1<=j<=i<=n && j<=m,状态转移方程为:
Status[i][j]=Max(Status[i-1][j]+Num[i],Max(Status[0][j-1]~Status[i-1][j-1])+Num[i])
乍看一下这个方程挺吓人的,因为题中n的限定范围为1~1,000,000而m得限定范围没有给出,m只要稍微大一点就会爆内存。但仔细分析后就会发现Status[i][j]的求解只和Status[*][j]与Status[*][j-1]有关所以本题只需要两个一维数组即可搞定状态转移。
在进行更进一步的分析还会发现其实Max(Status[0][j-1]~Status[i-1][j-1])根本不需要单独求取。在求取now_Status(保存本次状态的数组)的过程中即可对pre_Status(保存前一次状态的数组)进行同步更新。
状态dp[i][j]
有前j个数,组成i组的和的最大值。
决策: 第j个数,是在第包含在第i组里面,还是自己独立成组。
方程 dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-1][k] ) + a[j] ) 0<k<j
空间复杂度,m未知,n<=1000000, 继续滚动数组。
时间复杂度 n^3. n<=1000000. 显然会超时,继续优化。
max( dp[i-1][k] ) 就是上一组 0....j-1 的最大值。我们可以在每次计算dp[i][j]的时候记录下前j个
的最大值 用数组保存下来 下次计算的时候可以用,这样时间复杂度为 n^2.
这道题是一段连续区间最大和的升级版,主要思想就是把当前段的最优值记忆下来,最优值为k段最优并上当前值
或k-1段的最优值加上当前值。。。模拟一下一组数据就能体会
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int N = 1000000+11;
const int inf = -0x3f3f3f3f;
int dp
, dp1
, v
;
int main()
{
int m, n;
while(scanf("%d %d", &m, &n)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(dp1,0,sizeof(dp1));
for(int i=1;i<=n;i++)
scanf("%d",&v[i]);
int flag;
for(int k=1;k<=m;k++)
{
flag=inf;
for(int i=k;i<=n;i++)
{
dp1[i]=max(dp1[i-1]+v[i],dp[i-1]+v[i]);
dp[i-1]=flag;
flag=max(flag,dp1[i]);
}
}
printf("%d\n",flag);
}
return 0;
}
相关文章推荐
- hdu 1024 Max Sum Plus Plus 一串数字中,m段连续数字最大和 滚动数组+dp
- HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
- HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
- HDU - 1024 Max Sum Plus Plus(最大M段连续子段和,详细解释)
- !HDU 1024 Max Sum Plus Plus-dp-(分组dp?最大分段子序列和)
- HDU 1024 Max Sum Plus Plus(dp最大m子段和)
- 【m段最大连续子段和的和】HDU - 1024 Max Sum Plus Plus
- HDU 1024 Max Sum Plus Plus求前n个数中的若干个数分为连续的m段的最大和值(解析)
- hdu 1024 Max Sum Plus Plus(dp求m个不相交子段和的最大值)
- HDU 1024 Max Sum Plus Plus[dp](最大m子段和)
- HDU 1024 Max Sum Plus Plus[dp](最大m子段和)
- 【HDU 1024】Max Sum Plus Plus(DP+滚动数组优化+最大m段字段之和)
- hdu 1024 Max Sum Plus Plus(dp && 最大m子段和)
- hdu 1024 Max Sum Plus Plus(DP最大字段和)
- HDU - 1024 Max Sum Plus Plus (多段最大连续和+状态压缩)
- hdu 1024 Max Sum Plus Plus m段连续子序列最大和 dp
- hdu 1024 Max Sum Plus Plus(DP最大字段和)
- hdoj Max Sum Plus Plus 1024 (DP) m个连续数组最大和
- dp基础-1 A - Max Sum Plus Plus HDU - 1024
- HDU 1024 Max Sum Plus Plus(最大M段和)