一种另类的思维——序列分割

原网址nurivf blog序列分割新方法

我们知道序列分割是一道很经典的斜率优化问题,可以在NK时间内解决。
现在我们用一种新颖的做法,使复杂度降至N log inf。这样N与K都可以开到更大的范围。
题意及斜率优化做法参见我写的斜率大法题库。

为了方便,我们将本题转化为:给定一个含n个数的序列,将这个序列划分为k段,使得每一段的平方和的总和最小
记s[i]表示前i个数的前缀和
那么我们可以得出这样一个方程
f[i,k]=min{f[j,k-1]+(s[i]-s[j])^2} (方程1)
这个方程受到了状态k的限制,因此这个方程的复杂度为O(nk),状态k也是解法1的时间复杂度不能低于O(nk)的根本原因。(其实解法2也可以将解法1的方程搬过来优化,只不过为了方便,我们在这里将方程写成另一种形式)

现在,我们仔细观察下上面的方程,通过上面的方程,我们可以联想到:
f[i]=min{f[j]+(s[i]-s[j])^2}+c (方程2)
这个是斜率优化的非常经典的方程,也可以说是一个模板方程
这个方程对应的也是一个区间划分问题,在这个问题中,最后可能将原始区间划分为1段,2段,3段,或者是n段……
而究竟划分成多少段,正是由这个c决定的。
当c由小到大取遍[0,inf)中的每一个数时,区间划分的段数也由大到小取遍n至1中的每一个值。(这个性质非常关键,正是本题的核心所在)

而在本题中,我们没有c这个东东,我们有的只是”必须划分成k+1段”的限定。
而这个划分k+1段的方案,也必定对应于一个特殊的c,这个c使得方程f[i]=min{f[j]+(s[i]-s[j])^2}+c能将原始序列划分为k+1段。

因此,我们可以二分c。每一个c都对应于一个段数,当c十分接近inf时,段数肯定就为1;当c=0时,段数就为n。
我们在二分c的时候,同时用dp检查一下段数是多少(O(n)的时间),如果段数正好为k+1,那么我们的方程2得到的结果,也就是方程1dp的最终结果再加上c(k+1)。
我们将此时的f[n]减去c(k+1),即可得到平方和的最小值minsum。
我们再将所有数的和的平方(s[n]^2),减去minsum,再将这个结果除以2,最终得到的就是本题的答案。
时间复杂度O(log(inf)*n)

因此,本题的k也就可以继续加强到100000以上的数量级

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值