最大子段和系列题目

一、最大子段和
n个数a[1]到a[n],求一段连续非空区间使和最大。
f[i]=max(f[i-1]+a[i],a[i])
ans=max{f[i]}
复杂度O(n)

二、最大两段和
n个数a[1]到a[n],求两段不重叠的连续非空区间使和最大。
注意这两段可以是挨在一起的…即可以为一个长度>=2的连续区间
我们设f1qzm表示I中f1的前缀max,即f1qzm[i]=max(f1qzm[i-1],f1[i])。
注意到我们一定是在某一个最大子段和后面添加东西。
可以由上一个元素结尾的最大两段和后面接上,也可以由这个元素之前的任意一个最大子段和后面另添一段,所以这里取前缀max。
f2[i]=max(f2[i-1]+a[i],f1qzm[i-1]+a[i],a[i])
ans=max{f2[i]}
注意边界要初始化为-inf。
复杂度O(n)

三、最大k段和
n个数a[1]到a[n],求k段不重叠的连续非空区间使和最大。
有了上一题好像这就很简单了。
fk[a][b]表示以b结尾的最大a段和。
维护一个二维前缀max fkmax[a][b]。
fk[a][b]=max(fk[a][b-1]+a[b],fkmax[a-1][b-1]+a[b],a[b])
感觉非常简单对吧23333~
复杂度O(nk)

四、动态最大子段和
n个数a[1]到a[n]。
q次查询,每次动态指定l,r,求a[l]~a[r]的最大子段和。
我们需要解决的问题是对于两段区间a[x]~a[y],a[y+1]~a[k],如何合并子段和信息。
如果子段和在两段内的话,那么更新两端的子段和。
如果子段和跨两端的话,那么一定是a[x~y]的一个后缀拼上a[y+1~k]的一个前缀。
那我们只要维护a[x~y]的后缀和的后缀max以及a[y+1~k]的前缀和的前缀max就行啦~
那我们用线段树维护每一段区间的动态子段和以及前缀和的前缀max和后缀和的后缀max,就可以妥妥地过了~
不对,好像有一些问题。
现在子段和可以合并了,但是前缀和的前缀max和后缀和的后缀max怎么合并呢…
其实很简单,我们再维护一个区间和sum。
这样的话前缀和的前缀max不然就是a[x~y]的前缀和的前缀max,不然就是a[x~y]的sum加上a[y+1~k]的前缀和的前缀max。
那后缀和的后缀max不就同理了吗~
然后我们合并结果和建线段树就都可以这么搞了。复杂度非常低~
这段写的比较意识流…感到无语的话自己YY也是很容易的啦~
O(n建树+qlognloglogn查询)
PS:我实际写起来发现查询时需要一个排序,这样可能会变成qlognloglogn,所以修改了复杂度。

五、环状最大子段和
n个数a[1]到a[n],但是这回连成了一个环,a[n]和a[1]是连在一起的。还是询问最大子段和。
首先我们想的肯定是破环成链,不过把a[1]~a[n]复制一份显然不好维护。
这时候我们想到了四…
如果子段和是没有跨过a[n]~a[1]的话,那么就直接当一做就行啦。
如果子段和跨过了a[n]~a[1],那么它必然是一段前缀+一段后缀。
预处理出后缀和的后缀max,然后枚举前缀的结尾,加上后缀和的后缀max,更新答案就行啦。

六、环状最大两段子段和
还是连成环的a[1]~a[n]。和二一样询问最大两段和。
破环成链好像还是行不通的,我们可以像五一样做吗?当然可以。
如果子段和是没有跨过a[n]~a[1]的话,那么就直接当二做就行啦。
如果子段和跨过了a[n]~a[1],那么它必然是一段前缀+夹在后缀和前缀中间的一段+一段后缀。
咦好像和二中的f2很像!
对,我们维护前缀和的前缀max,设为qzhmax,后缀和的后缀max设为hzhmax。
那么此时f3[i]=max(f3[i-1]+a[i],qzhmax[i-1]+a[i],a[i])
那么答案就是max{f3[i]+hzhmax[i+1]}。

七、环状最大k段和
八、动态环状最大子段和
九、动态环状最大k段和
这些请众位dalao自行脑补23333

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值