【HDU 1024】Max Sum Plus Plus(DP+滚动数组优化+最大m段字段之和)
来源:互联网 发布:matlab数据分析案例 编辑:程序博客网 时间:2024/05/18 11:28
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. ^_^
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
题目大意
本题的大致意思为给定一个数组,求其分成m个不相交子段和最大值的问题。
思路
首先把问题分解为子问题,对于某一个状态想要得到最优解,那么这个状态的前一个状态必定为最优解(如果问题可以分为一个个子问题),对于本题试想:如果当前状态为j个数字分成i段,那么要保证其最优,考虑如下两种情况:
①:前j-1个数字分成了i段,那么第j个数字应该拼接接在这i段之后,到达新的转态即j个数字分成i段。
(i,j-1)+NUMBER(j)-->(i,j)
②前j-1个数字分成了i-1段,那么第j个数字应该单独成段,才能到达新的状态即j个数字分成i段。
(i-1,j-1)&&NUMBER(j)-->(i,j) (&&表示第j个数字单独成段)
要保证j个数字分成i段这个状态为最优,那么必须保证这个状态是由上述两种情况中i段之和最大的状态转换而来,即:
max((i,j-1)+NUMBER(j),(i-1,j-1)&&NUMBER(j))-->(i,j)
结合DP的思想可以定义dp数组dp[i][j]表示当前状态为j个数字分成i段,num[i]表示数列中第i个数,那么结合上述的结果可以得到状态转移方程:
dp[i][j]=max(max(dp[i-1][t])+num[j],dp[i][j-1]+num[j]) /*其中t的取值范围是:0<t<j;这边有必要解释一下max(dp[i-1][t])+num[j]和dp[i][j-1]+num[j],后者很容易理解就是将num[j]拼接在这i段之中。对于前者,因为要保证状态最优,所以必须先找到dp[i-1][t](i-1<t<j)中最大的一个,注意dp[i-1][j-1]肯定也是由他的前一个最优状态得来的,但是这个最优状态不一定代表着i-1段中有j-1个数字,只是说这j-1个数字分成了i-1段,因为要最优所以必定要舍弃一些数字保证子段和最大,也就是说dp[i-1][j-1]此时不一定是最大的(但是是这个状态最优的)。所以当我们将第i个数字单独成段时,必须找到dp[i-1][?]中最大的一个才能保证最优。*/
理解了这些再来考虑优化问题:
①:为什么要优化呢?我们来看数据范围:0<m<=n<1000000对于上面的做法,首先需要跑i:1->m表示分成1~m这些段,接着跑j:0->n表示j个数字分成i段,再接着跑t:i-1->n寻找max(dp[i-1][t]),可以近似的认为时间复杂度为:O(n^3),肯定超时。空间复杂度此处未知。②怎么优化呢?时间上:我们发现对于max(dp[i-1][t]),我们其实只要在前面的过程中把最大的记录在一个数组pre[t]中,那么就可以不用跑一遍循环而可以直接使用。空间上:因为最终的转态都是由一个个小状态逐步转换而来的,而转态是由最小的开始的,所以对于dp[i][j]我们可以优化为一维数组dp[j],因为我们在跑for(i:1->m)时是从1开始跑的,当跑到2时dp[j]中的数据就是dp[1][j]中的数据,我们可以直接使用。详细实现可以参见代码!
代码
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int maxn=1000000+5;const int INF=0x3fffffff;int dp[maxn],num[maxn],n,m,pre[maxn];int main(){ while(~scanf("%d %d",&m,&n)) { memset(pre,0,sizeof(pre)); int maxx; for(int i=1;i<=n;i++) { scanf("%d",&num[i]); } dp[0]=0; for(int i=1;i<=m;i++) { maxx=-INF; for(int j=i;j<=n;j++) { dp[j]=max(dp[j-1],pre[j-1])+num[j]; pre[j-1]=maxx; if(dp[j]>maxx) maxx=dp[j]; } } printf("%d\n",maxx); } return 0;}
- 【HDU 1024】Max Sum Plus Plus(DP+滚动数组优化+最大m段字段之和)
- hdu 1024 Max Sum Plus Plus 一串数字中,m段连续数字最大和 滚动数组+dp
- hdu 1024 最大M子段和 Max Sum Plus Plus(dp)(中等难度)
- HDU - 1024 Max Sum Plus Plus(DP + 滚动数组)
- hdu 1024Max 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(dp最大m子段和)
- HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
- hdu 1024 Max Sum Plus Plus(DP最大字段和)
- hdu 1024 Max Sum Plus Plus (最大m子段和)(经典DP)(转)
- HDU 1024 Max Sum Plus Plus (DP·滚动数组)
- DP+滚动数组-HDU-1024-Max Sum Plus Plus
- HDU 1024 Max Sum Plus Plus DP+滚动数组
- HDU 1024 Max Sum Plus Plus【DP+滚动数组】
- hdu 1024 Max Sum Plus Plus(最大M子段和)
- hdu 1024 Max Sum Plus Plus(最大m子段和)
- HDU 1024 Max Sum Plus Plus(最大M子段和)
- lake counting(dfs)
- java日历小程序
- 我的第一篇博客
- 多校1.Abandoned country1001
- linux下安装redis----查阅资料整理总结
- 【HDU 1024】Max Sum Plus Plus(DP+滚动数组优化+最大m段字段之和)
- HDU 2553 N皇后问题
- 文件存储openFileOutput和openFileInput
- zookeeper管理控制台安装
- bower使用入门
- [JQ权威指南]使用JQ读取JSON数据
- 1088. Rational Arithmetic (20)
- 构造性证明
- C#无边框移动