【APIO2014】Split the sequence

看到题之后第一想法就是斜率优化然后直接推式子了,却忽略了一个重要的前提就是和切的顺序无关,否则就应该是区间dp。(后怕)
这里来证明一下:如果分成三段分别为\(s_1,s_2,s_3\),若先1后2则为\(s_1 \times{(s_2+s_3)}+s_2\times{s_3}\) 否则为\(s_3 \times{(s_1+s_2)} +s_2\times{s_1}\) 拆一下就会发现完全相同。

然后考虑\(dp[i][k]\)表示前\(i\)个数分了\(k\)块的最大贡献,记\(calc(x,y)\)表示把\([1,y]\)\(x\)分开造成的贡献,答案为\(dp[n][k]\),转移为\(dp[i][k]=max_{j=1}^{i-1} dp[j][k-1]+calc(j,i)\)
这样直接做是\(O(n^2k)\)的,显然过不了,考虑优化。

拆一下\(calc(x,y)=(s[y]-s[x])\times{s[x]}\) 这样转移后面就是\((s[i]-s[j])\times{s[j]}\),显然可以斜率优化,点为\((s[j],s[j]^2)\) 然后手玩一下式子发现需要维护的是一个斜率递减的凸壳,至此斜率优化结束,时间复杂度\(O(nk)\),算是比较显然的做法,注意需要优化一下空间,滚动数组固然可以但是空间没有超太多只需要优化一个队列数组就行。

但是事实上我们可以出一个复杂度与k无关的加强版,需要再观察点性质。
看到分\(k\)次这个关键词,我们可以想到wqs二分,现在来尝试证明一下这个是一个凸函数。不妨换一个角度考虑答案,如果分的块已经确定了,答案就是每个块与它后面块和的乘积再sum起来。经典套路是把答案乘2变为每个块乘上除了这个块以外和的乘积再sum,然后这样又可以改写为总和乘总和减去sigma块和^2。
考虑g(i)表示分i次贡献最大值,我们考虑在g(i-1)的基础上再加一个点,根据贡献的计算我们需要让sigma(s[i]^2)尽可能小,所以一定会在最大的s[i]的中点处再选一个,每次减的只会越来越少,所以(i,g(i))是一个斜率递减的凸函数。

分析完之后就是wqs二分的模板,考虑枚举直线的斜率来切凸包,使得正好切在x=k处,注意做线性dp的时候也是要用斜率优化的。至此wqs二分做法结束,复杂度\(O(nlognA)\)

Submission:
斜率优化:https://uoj.ac/submission/609760
wqs二分:https://uoj.ac/submission/444702,https://uoj.ac/submission/261850

posted @ 2023-03-06 15:58  IceYukino  阅读(44)  评论(0)    收藏  举报