[学习笔记]斜率优化

斜率优化顾名思义,主要是通过斜率来确定当前 dp 需要取的最大值或者是最小值这类的。

比如说我们要处理 \(a,b\) \(ax+by\) 的最大值。

这里假设 \(a,b>0\)

那么我们先画出 \(ax+by=0\) 的图像,显然这是一条过原点的直线。

这里取得是 \(5x+3y=0\)

img

我们可以将其平移,平移的结果就反映了 \(ax+by\) 的变化结果比如

img

这是 \(5x+3y=1\) 所以我们知道了,我们 dp 结果为 \(1\) 的都在这条直线上。

那么我们就是要找这条直线斜率不变左右平移的最远点。

主要是处理 dp 柿子长这样 : \(dp_i\) 等于 \(j\) 相关 \(\pm\) \(f(j) \times g(i)\) + \(i\) 相关。

这里要把 \(g(i)\) 看成斜率通常。

P3195 玩具装箱

这道题目实际上就是要求:我们把这些东西分成若干个小块后每段长度 -L 后平方的最小值。

img

我们可以做一个等价转换。中间的我们不计算,而是把所有的 \(c\) 全部加 1,然后发现每段多算了 \(1\),那么就把 \(L\) 也 +1。

我们能很轻松的写出 dp,\(dp_i\) 表示前 \(i\) 个已经匹配好了的最小的值。

\(dp_i=\min\{dp_j+(sum_i-sum_j-L)^2\}, j\in[1,i)\)

因为对于这个柿子计算, \(sum_i\)\(L\) 都是常量,我们选择合并,叫做 \(sum_i'\),那么柿子再展开一下变成了 \(dp_i=\min\{dp_j+sum_j'^2-2sum_jsum_i'\}+sum_i'^2, j\in[1,i)\)

这样是不是就是我们上面所说的柿子了?

我们可以把 \(sum_j\) 看成 \(x\)\(2*sum_i'\) 看成斜率,把 \(dp_j+sum'j^2\) 看成 \(y\)。那么这个柿子不就变成了 \(dp_i=\min\{y-kx\}+sum_i'^2, j\in[1,i)\)。我们这样就成功把这个柿子化成了一个上面所说的模样。

柿子已经是上面那个东西了,那么接下来我们应该怎么做呢?

按照之前讲的,我们应该找这个斜率的直线平移到一个极限位置。而这个极限位置算出来的答案就是最值。

img

我们会发现,只有外面一圈的点是有用的,红色阴影区域的点是无用的。那么我们想到维护外面一圈凸壳就好了。

是不是真的要维护一个凸壳呢?

实际上并不用,注意到 \(sum\) 数组是递增的。那么说明斜率也是递增的。

这说明什么?这说明我们只需要维护一个斜率以及 \(x\) 不会减的下凸壳就好了,这怎么操作?

首先,如果我们现在的斜率已经大于了凸壳第一个点和第二个点的斜率,那么第一个点是不是没用了。(如下图)

img

红色的线只会逆时针旋转,所以不可能再把最左边的点搞到凸壳上了。

那么左边可以退出了,右边如何加点呢?

img

最右边两个点的斜率大于了右边第二个点和右边第三个点的斜率,说明下凸包不满足要求了,所以不断弹出,把右边第二个和右边第三个全弹出了。

至此,我们已经可以 AC 此题了。

posted @ 2022-11-12 21:41  Mercury_City  阅读(88)  评论(0编辑  收藏  举报