斜率凸优化小结

斜率凸优化小结

前言

很久以前考了一道叫做"林克卡特树"的题目( 还记得被八省联考支配的恐惧吗?)
正解是用直线去切一个凸函数......
当时并不是很会。然而(APIO)讲课竟然讲了并且卧槽我竟然还听懂了。
所以就回来把这个坑给填了。

斜率凸优化

当遇到关于需要恰好选取(K)个的(DP)问题的时候,
一般做法就是在(DP)数组上再设一维。这样做时间代价是(O(n))的。
其实不如给每次选取加一个权值(C)
那么每次选取就需要付出(C)的代价。所以(C)越大选的越少,(C)越小选的越多。
所以?二分(C)即可。时间代价变为(O(logn))
形象的来说,对于(DP)数组,取(E)个时的答案(best(E))是一个上凸的。
所以我们用(f(x) = Cx)这条直线去切这个上凸包,直到(best(K)-KC)是最优的。
那么此时选取的个数就是题目所需的(K)个了。
下面给一张图(引用自cjfdf):

例1:[APIO2014]序列分割

题目戳这里
可以发现,对于不在同一段的任意两个元素(a),(b),都对答案有(ab)的贡献。
所以处理出前缀和(pre)
那么转移:(f_{i,j} = max{f_{k,j-1} + pre_k * (pre_i - pre_k)})
斜率优化不解释,复杂度(O(nK)),可以直接通过原题。
如果(K leq 200) 变为(K leq n)呢? 直接斜率凸优化即可,复杂度(O(nlogK'))
代码戳这里

例2:[八省联考2018]林克卡特树lct

题目戳这里
本质上就是要选择出(K+1)条不相交的路径使它们的权值和最大。
考虑树形(DP)。设(f_{u,j,0/1/2})分别表示(u)点的度数为(0/1/2)时的最优解。
定义(Ans_{u,j})表示(max{f_{u,j,0/1/2}})
转移:
对于(f_{u,j,0})有:

  • (f_{u,j,0} = max{ f_{u,j-t,0} + Ans_{v,t} })

对于(f_{u,j,1})有:

  • (f_{u,j,1} = max{ f_{u,j-t,1} + Ans_{v,t}})
  • (f_{u,j,1} = max{ f_{u,j-t,0} + f_{v,t,1} + Edge_{u,v}})
  • (f_{u,j,1} = max{ f_{u,j-t-1,0} + f_{v,t,0} + Edge_{u,v}})

对于(f_{u,j,2})有:

  • (f_{u,j,2} = max{ f_{u,j-t,2} + Ans_{v,t}})
  • (f_{u,j,2} = max{ f_{u,j-t+1,1} + f_{v,t,1} + Edge_{u,v}})

上述转移复杂度(O(nK^2)),不够优秀。
发现对于 表示选择个数的第二维(j) 可以进行斜率凸优化。
直接斜率凸优化即可,复杂度变为(O(nlogK'))。实现代码戳我

原文地址:https://www.cnblogs.com/GuessYCB/p/9051438.html