您的位置:首页 > 其它

最大子段和系列题目

2017-08-11 23:09 176 查看
一、最大子段和

n个数a[1]到a
,求一段连续非空区间使和最大。

f[i]=max(f[i-1]+a[i],a[i])

ans=max{f[i]}

复杂度O(n)

二、最大两段和

n个数a[1]到a
,求两段不重叠的连续非空区间使和最大。

注意这两段可以是挨在一起的…即可以为一个长度>=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
,求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


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,就可以妥妥地过了~

不对,好像有一些问
4000
题。

现在子段和可以合并了,但是前缀和的前缀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
,但是这回连成了一个环,a
和a[1]是连在一起的。还是询问最大子段和。

首先我们想的肯定是破环成链,不过把a[1]~a
复制一份显然不好维护。

这时候我们想到了四…

如果子段和是没有跨过a
~a[1]的话,那么就直接当一做就行啦。

如果子段和跨过了a
~a[1],那么它必然是一段前缀+一段后缀。

预处理出后缀和的后缀max,然后枚举前缀的结尾,加上后缀和的后缀max,更新答案就行啦。

六、环状最大两段子段和

还是连成环的a[1]~a
。和二一样询问最大两段和。

破环成链好像还是行不通的,我们可以像五一样做吗?当然可以。

如果子段和是没有跨过a
~a[1]的话,那么就直接当二做就行啦。

如果子段和跨过了a
~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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: