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

原网址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以上的数量级

你可能感兴趣的:(一种另类的思维——序列分割)