斜率优化笔记
斜率优化笔记
前置知识
在阅读前你需要掌握:
- 单调队列
- 线性动态规划
应用场景
斜率优化是一类动态规划优化算法,应用于一类特殊的线性dp问题,当求得当前状态的表达式需要用先前所有状态求最大或最小值时,它可以构造一种类似单调队列的优化,将转移由暴力的\(\Theta(n^2)\)提升到线性。形式化地,它一般用于这种转移:
初步推导
对于求最大、最小值的优化问题,一个朴素的思路是考虑先比较两三个不同选项,找出区分它们优劣的条件。具体地,构建一个函数,通过函数值的大小范围来表示两个选项的优劣,这是一种常见技巧。
对于这题,考虑上式中\(j\)去\(a, b\)的两种情况,并规定我们要求最小(最大的情况是类似的),同时让决策\(a\)不比\(b\)劣。
注意到\(-g(i)\)对于特定的\(i\)是一个常数,考虑把它放在不等号一侧,这时候我们要把一个式子除过不等号,注意讨论处理。
首先要考虑这个式子是不是0:如果\(h(a)=h(b)\),那么式子和\(g(i)\)无关,那么对于不同的\(i\)优劣情况相同,在单调队列遇到这种情况,直接特判比较\(t\),删掉大的即可。
然后考虑它的正负性,正负性如果要讨论是不好的,后续研究不下去,毕竟我们是要推出普遍规律的。但是,注意到这里参与比较的,都是前面已经处理完的式子,且彼此之间独立,参与比较的顺序没有关系。所以,我们可以在遍历\(j\)的时候做一些处理,让所有的\(h(j)\)降序排列,那么符号问题就没有了。这个地方为了维护\(h(j)\)降序,在一些题目中可能要用set
维护状态,复杂度可能多一个\(log\)。
接下来解决了这个移项的问题,继续推就可以得到一个函数\(r(a, b)=\frac{t(a)-t(b)}{h(a)-h(b)}\),使得\(a\)不比\(b\)劣当且仅当\(r(a,b)\le -g(i)\)。
核心思路
斜率优化的核心,就隐藏在\(r(a,b)\)这个比较函数中。基于\(r(a,b)\)的比较必须在已知一个特定的\(h(i)\)时进行,所以我们不能复用计算出的一些信息。如果可以在不考虑\(i\)的情况下无条件排除一些情况,那么动态规划的速度就能可能有质的飞越。
我们可以考虑比较\(r\)的函数值,具体地,当\(r(a,b)\le r(b,c)\)时,考虑如果\(b\)比\(c\)劣,我们就选\(c\)而不选\(b\);而如果\(b\)不比\(c\)劣,那么\(r(a,b)\le r(b,c)\le -h(i)\),我们可以直接推知\(a\)不比\(b\)劣,于是选\(a\)而不选\(b\)。这就告诉我们,\(b\)这个状态无条件地没有用,可以直接排除。
总结一下我们目前做的事情:我们给出了一种方法来排除无条件不优的状态,并得以维护一个决策的序列。对于这个序列中的任何一个决策\(j\),存在一些\(i\)使得它是最优的决策,以及对于另外一些\(i\)使得它不最优。同时这个序列中的决策\(j\)按照一个特定顺序排列,使得所有的\(r(j,j+1)>r(j+1,j+2)\)。之所以先前我说“动态规划的速度就可能有质的飞越”是因为虽然剪去了无条件更劣的条件,但我们还不能利用这一点性质,对于每一个\(i\)在\(\Theta(\log_2 n)\)以内求出最优决策。下面的任务,就是利用维护的决策序列进行转移。
考虑一个决策\(j\),改变\(i\)其实就是在改变比较函数\(r\)不等式右边的\(-g(i)\)。对于任何的g(i),由于\(r\)的单调性,一个显然的结论是前面的一些\(r(j,j+1)\)比\(-g(i)\)大,后面的则不比它大。于是这个转折点的决策就是最优的决策。因为\(r(j,j+1)\)单调降,所以可以对于每个\(i\)进行二分,在\(\Theta(\log_2 n)\)时间复杂度内完成单次转移,整体时间复杂度就从\(\Theta(n^2)\)优化到了\(\Theta(n\log_2n)\)。