斜率优化

斜率优化


1.概念

对于某些转移方程形如(DP[i] = min / max(DP[j] + f(j)))的DP来说,我们可以使用单调队列将其由(O(n^{2}))优化为(O(n))。但对于一些转移方程形如(DP[i] = min / max(DP[j] + f(i , j)))的DP来说,因为转移中有与(i)有关的表达式,于是就不能贸然地使用单调队列了。这个时候我们需要将斜率优化请上台面。

我们以转移方程形如(DP[i] = min(DP[j] + f(i, j)))的DP为例。

尝试将DP方程化为(DP[i] = {color{red}{(……)}} + {color{green}{(……)}} +{color{orange}{(……)}})的形式。红色的部分为仅与(j)有关的表达式,绿色的部分则与(i)(j)均有关,橙色的部分只与(i)或常数有关。设红色部分为(y),绿色的部分中与(i)有关的部分为(k),与(j)有关的部分为(x),橙色的部分向左移项与(DP[i])合为(B),这样我们就将其化成了(B = y - kx)的形式,整个问题就转化成了求(B)最小。因为在(B)中与(i)有关的部分在单次转移时相当于一个常数,所以求(B)最小就相当于求(DP[i])最小。

对于任意(j),可以表示为坐标轴上一点((x, y)),转移时则可利用坐标计算(y - kx),求得(B)的最小值(当然算的时候别忘了计算(B)中的常数)。保证斜率(k >0),且随(i)单增,才可以进行下面的转移。

如何确定转移最优一点呢?这样:

example 1

将斜率为(k)的直线上移,可发现第一个触及直线的点会使其截距最小。而又因为斜率单增,所以说此点前的所有点已经对转移没有贡献,直接弹出即可。

如果尾部在插入新的(j)时出现了不下凸的情况怎么办?这样:

example 2

(i)点之上的两个点在(i)点插入后,将不会有对转移做出贡献的机会,因为由(i)点转移至当前点时所得到的截距将恒优于(i)点之上的两个点。所以此两点一并弹出即可。

或使用数学方法证明:记(slope(i, j) = dfrac{Y(i) - Y(j)}{X(i) - X(j)}),当前点为(l)。若(slope(i, j) < k (i < j)),则说明由(j)转移到(l)较由(i)转移到(l)更优。假设(slope(i, j) > slope(j, l)),若(slope(j, l) < k),则(l)(j)更优;若(slope(j, l)>k),则(slope(i, j)>k),说明(i)(j)更优。

这样的话不论怎样,出现上凸的(j)点都不会是更优的转移点,所以说直接将(j)点删除,再(i,l)相连即可。

存点的结构考虑单调队列,因其可以按条件进行双向删除,单向插入,符合需求。

维护队首时,比较(slope(head, head + 1))是否小于(k)。小于(k)说明此点在所求点之下,弹出。第一个(slope(…) geqslant k)的点即为所求转移点。(PS:如果弹到队尾都没有符合要求的点,则至少要留下一个点转移。)

维护队尾时考虑上述证明,弹出(slope(tail, i) < slope(tail - 1, tail))(tail)。这个就不用留点了,因为到最后还会插入一个(i)

成型后的有效点集大概这样,是个上凸包。

example 3

大概就这样。

那么如果(k)(i)单减,转移方程求的是最小值呢?维护一个上凸包即可(维护单调队列时把小于号都反过来)。

上面所说的均是(x)单调且(k)单调的情况,那如果它们不单调呢?据说(x)不单调可以开平衡树或cdq分治,(k)不单调二分查找。然而我并不会:P

没了。

2.例题

直接看博客即可。

1.[HNOI 2008]玩具装箱

传送门

2.[USACO08MAR] 土地购买 Land Acquisition

传送门

有不正确之处请不吝赐教。评论区在下方,若评论框过小右下角拖动即可。谢谢。

原文地址:https://www.cnblogs.com/manziqi/p/9160365.html