首页 > 其他分享 >[题解]HDU1024 Max Sum Plus Plus

[题解]HDU1024 Max Sum Plus Plus

时间:2024-03-24 21:47:37浏览次数:25  
标签:maxx int 题解 Sum leq Plus 优化 dp

HDU 1024

这道题是一道很巧妙的\(dp\)题(虽然优化成一维,可是究其本质算不算二维\(dp\)?如果有明白的麻烦在评论说一下多谢),在上一篇文章——线性\(dp\)模型中也提到过,因为其前身其实就是上一篇写到的「最大连续子段和」。只不过这一题问的不是一段,而是\(m\)段,所以较上一题我们的选择更加自由。

(HDU注册上让验证手机号,结果愣是一直没收到验证码,而一天最多只能发\(3\)次,所以暂时没法测试自己的代码,但是目前和正解对拍是对的)

题意简述

多测,每次给你\(n\)个数,要求从中选出\(m\)个没有公共部分的连续子段,求这几个连续子段的和的最大值。

数据范围:\(1\leq m\leq n\leq 10^6\)(奈何\(m\)和数据组数具体范围都没给,因为\(m=10^3,n=10^6\)这个数量级就已经不可做了)

解题思路

用\(dp[i][j]\)表示以第\(j\)个元素结尾,分成\(i\)组的最大和\((i\leq j)\)。你可能会疑惑为什么不把\(i\)和\(j\)的含义反过来。别急,这是为了后期的优化。

我们用下列样例演示:

2 6
-1 4 -2 3 -2 3

如图,表示\(6\)个元素,取出\(2\)组的\(dp\ table\)(其实\(2\)行就够了,不过为了更好地演示我画到了\(n\))。

如图所示,递推式为\(dp[i][j]=max(dp[i][j-1],dp[i-1][k])+a[j](1\leq k<j)\),下面是推导过程:

  • 上一个元素在当前组,因为在当前组,所以必须是连续的,即只有\(dp[i][j-1]\)。
  • 上一个元素在上一组,而上一组可以和自己连续也可以不连续,所以有\(dp[i-1][k](1\leq k<j)\)。
  • 上面两种情况取个最大值,别忘加上自己(即\(a[i]\))。

我们发现每个格子的状态只和当前行和上一行有关,所以我们可以优化空间为一维。而上一行以下标\(i\)结尾的最大值我们可以用\(maxx[i]\)表示。其实与滚动数组很像,但是滚动数组只是优化了空间。

我们这个做法除了优化空间,还可以节省时间。因为如果没有\(maxx\)的预处理,我们根据上面第二个步骤计算上一排的最大值时需要循环遍历,浪费时间。这样预处理,节省空间和时间,一举两得。

时间复杂度为\(O(Tnm)\)

*注意:可能需要输入优化(数据量比较大,题目中也有提到)

Code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int m,n,a[1000010],dp[1000010],maxx[1000010];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>m>>n){
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		memset(dp,0,sizeof dp);
		memset(maxx,0,sizeof maxx);
		for(int i=1;i<=m;i++){
			for(int j=i;j<=n;j++){
				dp[j]=a[j]+max(dp[j-1],maxx[j-1]);
			}
			for(int j=i;j<=n;j++){
				maxx[j]=max(maxx[j-1],dp[j]);
			}
		}
		int ans=INT_MIN;
		for(int j=m;j<=n;j++) ans=max(ans,dp[j]);
		cout<<ans<<endl;
	}
	return 0;
}

标签:maxx,int,题解,Sum,leq,Plus,优化,dp
From: https://www.cnblogs.com/Sinktank/p/18092722

相关文章

  • AtCoder Beginner Contest 346 题解
    A-AdjacentProductQuestion给你\(N\)个整数\(A_1,A_2,\dots,A_N\)。同时,定义\(B_i=A_i\timesA_{i+1}\(1\leqi\leqN-1)\)按此顺序打印\(B_1,B_2,\dots,B_{N-1}\)Solution按照题意模拟Code#include<bits/stdc++.h>usingnamespacestd;intmain......
  • AT_abc344_D-String Bags 题解
    明显是DP。然后就开始分析:状态:\(dp_{ij}=\)有\(i\)个袋子且匹配\(T\)的前缀的长度为\(j\)时所需的最少钱数。匹配\(T\)的前缀的长度为\(j\)就是前\(j\)个字符与\(T\)的前\(j\)个字符相同。相对简单。然后看转移。为了方便,咱不妨令\(|S|\)为字符串\(S......
  • P10111 [GESP202312 七级] 纸牌游戏 题解
    看标签知道要用DP。于是开始分析。状态:$dp(i,j,k)=$前\(i\)轮中,第\(i\)轮出\(j\),一共换了\(k\)次牌的最大钱数。很好理解。转移也不难,不就是不换和换两种吗!所以,转移就是:\[dp(i,j,k)=\max\begin{cases}dp(i-1,j,k)+\operatorname{pk}(j,c_i)\times......
  • [暴力题解系列]2023年蓝桥杯-整数删除(30分)
    这题暴力最多30分,但是30分也是分,做暴力的人不能贪心,拿到分就是赚了。​ 这题核心烦人点在于他数据分层断崖,就只有前3个点能做到稳过。用的思路就是链表,但不是用指针存的,而是用数组下标为标记存的,只是我觉得因为这样好写一些。链表方便修改左右连接位置,所以越到后面就越能省下查询......
  • 0318-0324题解
    成信大天梯赛L1-6二进制因为二进制是逢二进一,所以我们只要用cnt记录一下每一位上的数并给它加起来,然后cnt%2便是其和这一位上的数,注意要从右往左开始点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>pii;voidsolve(){stringa,b......
  • 广州大学第十八届ACM大学生程序设计竞赛(同步赛)——题解
    这套题我答的很失败。没有按照题目的难度去答题,前期浪费了不少时间。题目:A-字符画题解:思维、模拟。这道题我的通过率为62.5,没有过的原因是因为对细节的处理和把控不到位,对一些点忽视,我也记录了搜索的过程,但没有把搜索过的点消掉,而且没有找到最好的顺序去解答这道题,我是按照横的......
  • 字母迷宫题解
    思路:看到这题一眼跑广搜,但是转眼天堂之门,欸为什么要加2?好像没法广搜(不满足广搜特性),咋办?凉拌。该怎么让它满足广搜特性(先搜到的是最优的)。欸,我们是不是可以将队列换成优先队列让先搜到的最优。好像是的欸,优先队列启动!代码:#include<bits/stdc++.h>usingnamespacestd;inta......
  • SUM-ACM——VJ天梯训练赛
    这次比赛我暴露了很多问题,一些模拟还有贪心思路错误。补题如下:E-E题解:一道模拟题,我的问题在于不知道怎么替换下一个,就从0开始遍历数组然后数组的值--,如果为零就continue下一个,这个问题在于无法遍历完所有的数,会少算。其实只需要把接完水的按顺序到下一个就可以了,这样还有一个......
  • cfEduRound163div2--D题解
    D-TandemRepeats?题意:做法:因为字符串长度较少,可以考虑枚举。or--动态规划voidsolve(){//D枚举//枚举!!!!!!!!!!stringstr;cin>>str;intn=str.size(),ans=0;for(inti=1;i<=n/2;i++){//枚举一半!!!intcnt=0;for(intj=0;......
  • 题解 CF1948G【MST with Matching】
    非常精彩的转化!显然,树是二分图。由König定理,我们知道:二分图最小点覆盖等于最大匹配。因此枚举点覆盖\(S\),则一条边\((u,v)\)可以被选择,当且仅当\(u\inS\lorv\inS\),在所有可以选择的边上跑最小生成树即可。我采用的是Kruskal算法,时间复杂度为\(O(2^nn^2\logn)\),可......