Loading

感性理解斜率优化

引入

考虑这样一个问题:给定数组 \(\{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)\)

这玩意的效果和二进制分组应该一样。

posted @ 2022-01-15 19:35  Alan_Zhao_2007  阅读(170)  评论(1编辑  收藏  举报