bzoj3675: [Apio2014]序列分割

bzoj3675: [Apio2014]序列分割

Description

小H最近迷上了一个分割序列的游戏。在这个游戏里,小H需要将一个长
度为N的非负整数序列分割成k+l个非空的子序列。为了得到k+l个子序列,
小H将重复进行七次以下的步骤:
1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的
序列一一也就是一开始得到的整个序列);
2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新
序列。
每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序
列中元素和的乘积。小H希望选择一种最佳的分割方案,使得k轮(次)之后,
小H的总得分最大。

Input

输入文件的第一行包含两个整数n和尼(k+1≤n)。
第二行包含n个非负整数a1,n2….,an(0≤ai≤10^4),表示一开始小H得
到的序列。

Output

一行包含一个整数,为小H可以得到的最大得分。

Sample Input

7 3

4 1 3 4 0 2 3

Sample Output

108

HINT

【样例说明】

在样例中,小H可以通过如下3轮操作得到108分:

1.-开始小H有一个序列(4,1,3,4,0,2,3)。小H选择在第1个数之后的位置

将序列分成两部分,并得到4×(1+3+4+0+2+3)=52分。

2.这一轮开始时小H有两个序列:(4),(1,3,4,0,2,3)。小H选择在第3个数

字之后的位置将第二个序列分成两部分,并得到(1+3)×(4+0+2+

3)=36分。

3.这一轮开始时小H有三个序列:(4),(1,3),(4,0,2,3)。小H选择在第5个

数字之后的位置将第三个序列分成两部分,并得到(4+0)×(2+3)=

20分。

经过上述三轮操作,小H将会得到四个子序列:(4),(1,3),(4,0),(2,3)并总共得到52+36+20=108分。

【数据规模与评分】

:数据满足2≤n≤100000,1≤k≤min(n -1,200)。

题目大意:

给定n个数,将这n个数划分为k+1个区间,使得每2个区间的和的乘积的总和尽可能大

分析:

解法1:

容易得知,划分区间的顺序对答案是没有影响的,证明如下:
不妨将原始序列分为3段,a,b,c分别表示3段区间的元素和
我们如果先从a,b间分割,再从b,c间分割,那么价值为a(b+c)+bc=ab+ac+bc
如果先从b,c间分割,再从a,b间分割,那么价值为(a+b)c+ab=ab+ac+bc
这两种方法得到的价值相等,也就说明划分区间的先后顺序不影响答案

那么本题就可以套用划分dp的模型了

记f[i,k]为前i个数通过划分区间得到的最大分数
s[i]为原始序列中第i个数到第n个数的后缀和
那么
f[i,k]=max{f[j,k-1]+(s[j+1]-s[i+1])s[i+1]}
然后通过对方程式进行变形(打公式好麻烦啊,这里就不再赘述了QAQ),最终可以得到

假设有2个决策 a,b,如果
公式
那么决策b会比决策a优

然后就没有然后了 经典的斜率优化 时间复杂度O(n*k) 空间复杂度可以用滚动数组优化到O(n)

解法2:

这个解法是本蒟蒻在网上通过多方查找,最后再加上本人稍稍yy得到的,如有不正确之处,还望各位大神指正
为了方便,我们将本题转化为:给定一个含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以上的数量级

你可能感兴趣的:(动态规划-斜率优化)