斜率优化dp
posted on 2024-11-03 06:03:21 | under | source
应用场景
考虑如下的 dp:
由于转移中含有 \(a_ib_j\) 这样的与 \(i,j\) 均有关系的项,所以不能简单的单调队列优化。
可以考虑决策单调性,不过有更好的办法:斜率优化。
算法步骤
先拆下式子:
长得很像一次函数的形式 \(y=kx+b\)。把问题放在平面直角坐标系上,那么 \(j\) 对应着一个点 \((b_j,f_j)\),那么一条斜率为 \(-a_i\) 的直线扫到该点时对应的截距就是我们要求的 \(f_i\)。
声明:下文都以求最大值为例。
于是问题变成了:维护一些决策点,每次询问将一条给定斜率的直线从上往下扫(最小值就是从下往上),找到第一个被扫到的点。
记 \(slope(i,j)\) 表示决策点 \(i,j\) 构成线段的斜率,那么当 \(slope(a,b)\le slope(b,c)\) 时,\(b\) 不可能成为最优决策点。如下图,形如下三角:

所以只需要关注这个上凸包就好了。
维护凸包的手段
最简单的一种
先考虑一种简单情况,假如新增点的横坐标具有单调性,比方说递增,那么拿个单调队列记录下当前凸包从左往右是哪些点,新增一个点,就看它能不能消掉队尾点(也就是队尾前一个点、队尾、新增点构成了下三角),一直消最后放到队尾即可。
不具有单调性
否则维护起来会比较麻烦,要用平衡树或者 cdq 分治维护,但是码量较大复杂度也一般,实际上可以使用李超线段树,见下文“询问”一节。
回答询问
对于斜率为 \(k\) 的询问,等价于找一个点,它和前一个点、后一个点的斜率为 \(k_1,k_2\),满足 \(k_1\ge k\ge k_2\)。
斜率具有单调性
不断消掉队首 \(p\),满足它跟后一个点的斜率 \(\ge k\),这样的话最后队首元素便是要找的那个。
不具有单调性
显然可以二分没什么好说的。
李超线段树
其实感觉和斜率优化没啥关系,斜优是:每次用直线扫决策点;李超树是:决策看成线,每次找最值。具体去找李超树博客吧。

浙公网安备 33010602011771号