首页 > 其他分享 >最大子段和问题及变式

最大子段和问题及变式

时间:2022-11-04 19:13:40浏览次数:77  
标签:最大 子段 max sum Way 题解 变式

最大子段和问题及变式 题解

Lim:除 T8,T9 外所有题目的 \(a_i\) 均可能为负,所有题目的 \(a_i\) 均为整数

T1 P1115 最大子段和

Tag: 线性dp / 单调队优线性dp / 分治,递归

题目描述:

给出一个长度为 \(n\) 的序列 \(a\) ,选出其中连续且非空的一段使得这段和最大。

题解:

Way 1: \(O(n\log n)\)

每次取一个中点,往下分治,往上递归。

Way 2: \(O(n)\)

\(f_i\) 表示以 \(a_i\) 结尾的最大子段和。

\(f_i=\max{(f_{i-1},0)}+a_i\)

对所有 \(f_i\) 取 \(\max\) 得到答案。

Way 3: \(O(n)\)

记 \(sum_i\) 为 \(\sum_{j=1}^ia_i\)

以 \(a_i\) 结尾的最大子段和也可以表示为: \(sum_i-\min_{j=1}^{i-1}sum_j\)

于是从 \(1\) 到 \(n\) 扫一遍,一边维护 \(\min_{j=1}^{i-1}sum_j\) 即可

Main Code: (Way 2)

for(int i=1;i<=n;++i) f[i]=max(f[i-1],0)+a[i],ans=max(ans,f[i]);

T2 子段长度不大于m的最大子段和

Tag: 单调队列优化线性dp

题目描述:

给出一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且长度不大于 \(m\) 的一段使得这段和最大。

题解:

参考 T1Way 3 : \(O(n)\)

以 \(a_i\) 结尾的最大子段和可表示为: \(sum_i-\min_{j=i-m}^{i-1}sum_j\)

于是从 \(1\) 到 \(n\) 扫一遍,一边利用单调队列维护 \(\min_{j=i-m}^{i-1}sum_j\) 即可

Main Code:

//Later to complete

T3 子段长度不小于m的最大子段和

题目描述:

给出一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且长度不小于 \(m\) 的一段使得这段和最大。

题解:

参考 T1Way 1 : \(O(n\log n)\)

每次取一个中,往下分治,往上递归。

参考 T1Way 2 : \(O(n)\)

先跑一遍T1: \(f_i\) 表示以 \(a_i\) 结尾的最大子段和, \(f_i=\max{(f_{i-1},0)}+a_i\)

再在每个 \(f\) 后拼上一个长为 \(m-1\) 的子串: \(f_i'=\max{(f_{i-1},0)}+sum_{i+m-1}-sum_{i-1}\)

对所有 \(f_i'\) 取 \(\max\) 得到答案。

参考 T1Way 3 : \(O(n)\)

以 \(a_i\) 结尾的最大子段和可表示为: \(sum_i-\min_{j=1}^{i-m}sum_j\)

于是从 \(m\) 到 \(n\) 扫一遍,同时维护 \(\min_{j=1}^{i-m}sum_j\) 即可

Main Code:

//Later to complete

T4 #A1045 环状最大子段和

题目描述:

给出一个长度为 \(n\) 的环状序列 \(a\) ,即 \(a_1\) 与 \(a_n\) 相邻,选出其中连续且非空的一段使得这段和最大。

题解:

Way 1: \(O(n)\)

断环成链,跑 T2 (子段长度不大于 \(n\) 的最大子段和)。

Way 2: \(O(n)\)

由于所有数的和 \(sum_n\) 是一定的,最大子段和 和 最小子段和 一定正好覆盖整个区间。

利用 T1 的方法,分别跑最大子段和 \(f_i\) 和 最小子段和 \(f_i'\) ,最后答案即为 \(\max{(\max_{i=1}^n{(f_i)},sum_n-\min_{i=1}^n{(f_i')})}\) 。

Main Code:

//Later to complete

T5 P2642 双子序列最大和

题目描述:

给定一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且不相交的两段使得这两段和最大。

题解:

T1 的方法,分别跑出 **以 \(a_i\) 结束的最大子段和 \(f_i\) ** 和 **以 \(a_i\) 开始的最大子段和 \(f'_i\) ** 。

之后 \(O(n)\) 枚举断点, \(ans=\max_{i=1}^{n-1}{f_i+f'_{i+1}}\) 。

<!!! 套路> 对于序列上两不相交区间的问题,枚举断点取最优解。两个区间的需求不相同时需要把区间信息分别按照两个区间的需求两次预处理。

这里有一道例题:P1091 [NOIP2004 提高组] 合唱队形

Main Code:

//Later to complete

T6 P1121 环状最大两段子段和

题目描述:

给定一个长度为 \(n\) 的环状序列 \(a\) ,即 \(a_1\) 与 \(a_n\) 相邻,选出其中连续非空且不相交的两段使得这两段和最大。

题解:

T4 + T5

T5 的方法跑出 双子序列最大和双子序列最小和 ,由 T4 可知这俩一样互补,接着用 T4 的思路跑就可以了。

Main Code:

//Later to complete

T7 最大m段子段和 (hdu1024 Max Sum Plus Plus)

Tag: 区间dp dp

题目描述:

给出一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且互不相交的 \(m\) 段使得这 \(m\) 段和最大。

题解:

Way 1: \(O(n^3m^2)\)

emm……这很区间dp。

令 \(f_{l,r,t}\) 表示区间 \([l,r]\) 内取出 \(t\) 段子区间的最大答案。

\(f_{l,r,t}=\max_{k=l}^{r-1}{\max_{p=0}^t{(f_{l,r,t},f_{l,k,p}+f_{k+1,r,t-p})}}\)

枚举 \(t\in[1,m]\rightarrow len\in[1,n]\rightarrow l\in[1,n-len+1]\rightarrow k\in[l,l+len-1]\rightarrow p\in[0,t]\) ,总复杂度 \(O(n^3m^2)\) 。

Way 2: \(O(n^3m)\)

注意到这是一个分段问题,与段数的分配无关,所以可以省掉转移式的最后一维,固定分别分配 \(t-1\) 个和 \(1\) 个段给左右两个区间。

image

如上图所示,假设绿色的三段是 \(f_{L,R,3}\) 的最优解,我们用 Way 1 的方法更新, \(f_{L,k1,1}+f_{k1+1,R,2}\) 、 \(f_{L,k2,2}+f_{k2+1,R,1}\) 和 \(f_{L,k3,2}+f_{k3+1,R,1}\) 都可以更新到该最优解,但重复更新浪费了时间。

指定分配方式后,该最优解只会被断点 \(k2,k3\dots\) 更新,而 \(k1\) 等重复更新情况被剔除,\(f_{L,k2,1}+f_{k2+1,R,2}\) 等无效更新大幅减少。可以保证正确性,同时优化掉了最后一层循环。

\(f_{l,r,t}=\max_{k=l}^{r-1}{(f_{l,r,t},f_{l,k,t-1}+f_{k+1,r,1})}\)

Way 3: \(O(n^2m)\)

考虑直接将上式中的 \(f_{k+1,r,1}\) 替换为 \(sum_r-sum_k\) 。 别问我咋想到的

为什么这样是对的呢?

image

设绿色区域为一个最优子段。一定存在一个时刻如图,使得这个区间恰好与 \([k+1,R]\) 重合参与更新。也就是说这样子做保证了每个区间都能被考虑,也就保证了正确性。

那么转移式就变成了酱紫:

\(f_{l,r,t}=\max_{k=l}^{r-1}{(f_{l,r,t},f_{l,k,t-1}+sum_r-sum_k)}\)

注意到修改之后的转移式中 \(f\) 的第一维下标全是 \(l\) ,也就是说都是在同一个 \(l\) 的基础上进行更新。考虑只更新 \(l=1\) 的情况,进而忽略第一维,所有更新都以 \(1\) 为左端点,不会出现未知更新已知的情况,即无后效性,并且依然可以涵盖所有子区间的信息。 别问我咋想到的*2

忽略第一维后, \(f\) 的定义变为:

令 \(f_{r,t}\) 表示区间 \([1,r]\) 内取出 \(t\) 段子区间的最大答案。

转移式变为:

\(f_{r,t}=\max_{k=l}^{r-1}{(f_{r,t},f_{k,t-1}+sum_r-sum_k)}\)

枚举 \(t\in[1,m]\rightarrow r\in[1,n]\rightarrow k\in[1,r]\) ,总复杂度 \(O(n^2m)\) 。

Way 4: \(Time:O(nm)\quad Memory:O(nm)\)

令 \(f_{i,j}\) 表示考虑以 \(a_i\) 结尾选出了 \(j\) 段的最大子段和。

\(f_{i,j}=\max{(f_{i-1,j-1},f_{i-1,j})}+a_i\)

// \(f_{i-1,j-1}\) :前 \(i-1\) 个数选出 \(j-1\) 个数, \(a_i\) 自成一段。

// \(f_{i-1,j}\) :前 \(i-1\) 个数选出 \(j-1\) 个数, \(a_i\) 接到最后一段尾巴上。

Way 5: \(Time:O(nm)\quad Memory:O(m)\)

滚动数组滚掉第一维即可,至此可以通过 hdu1024 。

Main Code:

//Later to complete

T8

Tag: 二分答案 尺取法

题目描述:

给定一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且最短的一段使得这一段和大于等于一个给定数 \(S\) 。

SP.Lim: \(a_i>0\)

题解:

注意,此题限制 \(a_i>0\)

Way 1: \(O(n\log n)\)

二分答案。

二分长度,然后跑 T2

Way 2: \(O(n)\)

尺取法。

双指针从左往右扫描一遍即可。

Main Code:

//Later to complete

T9

Tag: 尺取法

题目描述:

给定一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且最短的一段使得这一段和大于等于一个给定数 \(S\) ,并且使这一段的和尽可能小。

SP.Lim: \(a_i>0\)

题解:

注意,此题限制 \(a_i>0\)

Way 1:

T8 Way 1 相似,不过要在跑 T2 的同时维护子段和。

Way 2:

T8 Way 2 ,不用写了吧。

Main Code:

//Later to complete

T10

Tag:

题目描述:

给定一个长度为 \(n\) 的序列 \(a\) ,选出其中连续非空且最短的一段使得这一段和大于等于一个给定数 \(S\) 。

题解:

注意,此题不限制 \(a_i>0\) ,也就是说存在 \(a_i\) 为负。

Way : \(O(n\log n)\)

参考 T1 Way 3 ,我们要求的是 \(\min{(j-i)}\) ,使得 \(sum_i=\min_{k=1}^{j-1}{sum_i}\) , \(sum_j-sum_i\ge S\) ,即 \(sum_i\le S-sum_j\) 。

对 \(sum\) 离散化,开一个权值线段树(或权值树状数组),对每个 \(j\) 在树上二分找到最后一个满足要求(\(\max i\) : \(sum_i\le S-sum_j\) )的位置。 (说详细点就是:在区间 \([1,S-sum_j]\) 内寻找最后一个存在的数,权值线段树可以记录区间存在的数的个数来判断,树状数组上二分的方法详见 \(2022.10.25\ 测试\ T2\ 题解\) )。

Main Code:

//Later to complete

标签:最大,子段,max,sum,Way,题解,变式
From: https://www.cnblogs.com/hankpeng/p/16858831.html

相关文章

  • RecycleView根据内容自适应高度,最大高度限制
    前言recylceView日常开发经常使用到,默认高度自适应,如何增加最大高度限制如下:publicclassMeasureLinearLayoutManagerextendsLinearLayoutManager{privateintmax......
  • 人生最大的投资是自己
    这个世界上最大的秘密之一,人是需要反馈的一种动物,有了反馈,我们就可以不断自我修正,不断前行,甚至成“神”!投资世界里有三种人:投资人、股民和普通人。木子看过一篇文章,说人生......
  • 【JS基础】关于JS能表示的最大精度的问题
    看了好多文章,我还是比较认可这位博主的说法:https://www.codercto.com/a/107226.html本文只是自己做记录,是篇水文,大家可以直接访问上面链接哦~根据 IEEE754 标准,有......
  • 1668. 最大重复子字符串
    1668.最大重复子字符串方法一:暴力枚举classSolution{publicintmaxRepeating(Stringsequence,Stringword){char[]ch1=sequence.toCharArray();......
  • 最大似然估计和均方误差到底是什么关系
    在学习机器学习的时候,我对这两个概念产生了强烈的迷惑。于是补习了相关的知识。首先给出结论:“根据中心极限定理,误差服从正态分布,此时使得样本似然函数最大等价于使得MSE......
  • tf中求最大值、最小值
    一,tensorflow中有一类在tensor的某一维度上求值的函数。如:求最大值tf.reduce_max(input_tensor,reduction_indices=None,keep_dims=False,name=None)求平均值tf.reduc......
  • #yyds干货盘点# LeetCode 腾讯精选练习 50 题:二叉树的最大深度
    题目:给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。示例:给定二叉树[3,9,20,null,null,......
  • 两个数按位异或 按位或 按位与的最大值
    and:就是从最高的一位向下找,如果这一位为1的数多于两个就取出这些数,然后再取出的这些数里面继续下一位的一样的处理,我就用递归写的or:这个比较巧妙,也比较暴力,先每个数开一......
  • 野花--flexible中强制设置网页最大宽度和最小宽度
    因为flexible是使用的屏幕宽大来作为rem的计算值,因此我们在设计最大750px,以及最小320px的页面时,会出现页面会一直随屏幕变大而变大,大于750或者小于320因此设置强制最......
  • 力扣-152-乘积最大的子数组
    对于dp[i],如果nums[i-1]>0,dp[i-1]也>0,那就是dp[i-1]*nums[i-1]如果<0,>0,那就是nums[i-1]0,<0,那就是nums[i-1]<0,<0,那就是dp[i-1]*nums[i-1]同样参考最大子数和,还需......