感性理解斜率优化
引入
考虑这样一个问题:给定数组 \(\{c_n\},\{d_n\}\),求数组 \(\{f_n\}\) 满足 \(f_i=\min_{j<i}\{f_j+c_i\times d_j\}\)。\(c_i,d_i\) 可能为负数。
按 \(i\) 从小到大计算 \(f_i\),并将所有 \(j<i\) 的 \((d_j,f_j)\) 放在二维平面上。计算 \(f_i\),其实就是将平面上每个点的 \(y\) 加上 \(c_i\times x\),然后取全局最小的 \(y\)。
对于平面上的三个点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\)(\(x_1<x_2<x_3\)),若 \(\operatorname{slope}((x_1,y_1),(x_2,y_2))>\operatorname{slope}((x_2,y_2),(x_3,y_3))\),那么 \((x_2,y_2)\) 永远不是最优解。证明显然。
我们知道,一个下凸壳加上一条直线,仍然是一个下凸壳。于是,我们只需要维护一个支持插入点的下凸壳,计算 \(f_i\) 时在下凸壳内二分一个转折点即可。
一些题目只需要用单调队列维护,是因为其 \(d\) 数组具有单调性;有的甚至可以做到线性,是因为其 \(c,d\) 都具有单调性。
题目 \(1\)
\[f_0=0,f_i=\min_{0\le j<i} \{ f_j+d_j\times c_i \} \]其中 \(\{c_n\}\) 单调递增,\(\{d_n\}\) 单调递减。
当计算 \(f_{i+1}\) 时,\(\forall 0\le j\le i\),我们将 \((d_j,f_j)\) 放在下凸壳里。根据“引入”里的讨论,我们只需要求这个下凸壳加上一条直线后,它的 \(\min\) 是多少。但 \(c\) 是单调递增的,因此如果凸壳上有两个顶点 \((x_1,y_1),(x_2,y_2)\) 满足 \(x_1<x_2\) 且 \(y_1+x_1\times c_{i+1}<y_2+x_2\times c_{i+1}\),那么在之后的计算中(即计算 \(f_{(i+2)\dots n}\) 时),\((x_1,y_1)\) 都一定比 \((x_2,y_2)\) 优。所以计算前我们删除凸壳最左端的不优的决策,此时最优决策一定是最左端的决策。
当我们计算完 \(f_{i+1}\) 时,我们要将 \((d_{i+1},f_{i+1})\) 插入到凸壳中。但因为 \(d\) 单调递减,所以插入的位置一定是最左端。所以直接用双端队列维护即可。复杂度是线性的。
题目 \(2\)
\[f_0=0,f_i=\min_{l_i\le j<i} \{ f_j+d_j\times c_i \} \]其中 \(0\le l_i<i\)。
我们使用 well-known 的技巧!用线段树维护凸包,当一个节点对应的区间内所有位置都被填满了,就从左、右儿子把凸包归并上来。当查询时就拆分成 \(\log\) 个凸壳,在每个凸壳上二分即可。时间复杂度 \(\mathcal{O}(n\log^2 n)\)。
这玩意的效果和二进制分组应该一样。