斜率优化

[[TOC]]

前置知识:线性规划

斜率优化的思想其实和高中数学的线性规划有相似之处,因此建议没学过的同学先了解一下线性规划

这个视频讲解了高中的线性规划的相关知识 https://www.bilibili.com/video/BV1qg4y1v7Xy?p=4

一元一次函数:y=kx+by = k \cdot x + b,它的函数图像如下所示

figure1

其中k,bk,b为定值,kk为直线的斜率

由图可知如下的事实:

  1. 这条直线ll上的所有点(xl,yl)(x_l,y_l)都符合:ylkxl==dy_l - k \cdot x_l ==d或者反过来说:在坐标 轴上所有符合ykx=dy - k \cdot x = d的点会组成一条直线,这条直线就是ll
  2. BB为直线llyy轴的交点,同时也是直线ll上的点,所以yBkxB=dy_B - k \cdot x_B = d,此时xB==0x_B == 0, 所以得到: yB=dy_B = d

我们把这个距离称为截距.也就是说:直线ll上的所有点ylkxly_l - k \cdot x_l的值就是这个截距.

截距的性质

直线上的任意一个点的(y,x)(y,x)的差值yxy-x的值就是截距

斜率优化

问题: 如下图所示,有多个点aia_i分布在坐标轴上,有一条直线y=kx+by = k \cdot x + b,其中k>0k>0且为定值,bb可以变化(这意味着,直线可以上下平移),那么如何选择一点aia_i,使直线经过该点时,使bb值,也就是截距最小?

figure_2

当我们选取一了一条直线,那么这条直线的斜率kk就是固定的,此时只能上下平移的去移动这条直线,那么这个直线的截距bb就是变化的.根据[ Rbook: 单调队列]的思想:++排除不可能的点++.我们不禁会想哪些点是不可能的点?

从候选的点集中任意取三个点a,b,ca,b,c,如下图所示. 设K(i,j)K(i,j)为点i,ji,j之间的斜率,即K(i,j)=ΔyΔx=yjyixjxiK(i,j) =\frac{\varDelta y}{\varDelta x} = \frac{y_j - y_i}{x_j - x_i}. 且这三个点满足发下的条件:

  1. xa<xb<xcx_a < x_b < x_c
  2. K(a,b)=k1>k2=K(b,c)K(a,b) = k_1 > k_2 =K(b,c)

::: oneline

figure3_1

figure3_2

:::

定理11: k3=K(a,c)k_3 = K(a,c),k2<k3<k1k_2 < k_3 < k_1

先证明k3<k1k_3 < k_1.延长直线a,ba,b到达与y=xcy=x_c的交点ee.k1=K(a,b)=K(b,e)=yeybxexbk_1 = K(a,b)= K(b,e) = \frac{y_e - y_b}{x_e - x_b}.又因为k1>k2k_1 > k_2,所以yeybxexb>ycybxcxb=k2\frac{y_e-y_b}{x_e - x_b} > \frac{y_c-y_b}{x_c-x_b} = k_2.由定义可知:xe=xcx_e = x_c,所以yeyb>ycybye>ycy_e - y_b > y_c -y_b \Rightarrow y_e > y_c.由上得到:

k3=ycyaxcxa<yeyaxcxa=k1(a) k_3 = \frac{y_c - y_a}{x_c - x_a} < \frac{y_e-y_a}{x_c - x_a} = k_1 \tag a

再证明k2<k3k_2 < k_3.延长直线c,bc,b到达与y=xay=x_a的交点ff.k2=K(b,c)=K(f,b)=ybyfxbxfk_2 = K(b,c)= K(f,b) = \frac{y_b - y_f}{x_b - x_f}.又因为k1>k2k_1 > k_2,所以ybyaxbxa>ybyfxbxf=k2\frac{y_b-y_a}{x_b - x_a} > \frac{y_b-y_f}{x_b-x_f} = k_2.由定义可知:xf=xax_f = x_a,所以ybya>ybyfya<yfy_b - y_a > y_b -y_f \Rightarrow y_a < y_f.由上得到:

k3=ycyaxcxa>ycyfxcxf=k1(b) k_3 = \frac{y_c - y_a}{x_c - x_a} > \frac{y_c-y_f}{x_c - x_f} = k_1 \tag b

综合(a),(b)(a),(b)得到:k2<k3<k1k_2 < k_3 < k_1.

推论11: 截距大小与斜率之间的关系

figure_4

如图所示: k1k_1表示直线a,ba,b的斜率,直线l2l_2的斜率kl2<k1k_{l_2} < k_1,直线l1l_1的斜率kl1>k1k_{l_1} > k_1. 证明:

B(l,k,a)B(l,k,a)表示有一个斜率为kk直线ll且结过点aa的截距,B(l,k,a)=yakxaB(l,k,a) = y_a - k \cdot x_a.

1.当直线ll的斜率k1>klk_1 > k_{l}时,直线ll经过点的截距B(l,kl,a)<B(l,kl,b)B(l,k_l,a) < B(l,k_l,b).

证明: 因为k1>klybyaxbxa>klybya>kl(xbxa)k_1 > k_{l} \Rightarrow \frac{y_b - y_a}{x_b - x_a} > k_l \Rightarrow y_b -y_a > k_l \cdot (x_b - x_a),

B(l,kl,b)B(l,kl,a)=ybklxb(yaklxa)=(ybya)kl(xbxa)>0 \begin{aligned} B(l,k_l,b)- B(l,k_l,a) &= y_b - k_l \cdot x_b - (y_a - k_l \cdot x_a) \\ &= (y_b - y_a) - k_l \cdot (x_b - x_a) \\ &> 0 \end{aligned}

2.当直线ll的斜率k1<klk_1 < k_{l}时,直线ll经过点的截距B(l,kl,a)>B(l,kl,b)B(l,k_l,a) > B(l,k_l,b).证明方法同上.

综上: 当有两个点a,ba,bxa<xbK(a,b)>0x_a < x_b \land K(a,b) > 0时,直线llkk值如果小于K(a,b)K(a,b),那么经过aa的截距小于经过bb的截距.如果直线llkk的值如果大于K(a,b)K(a,b),那么经过bb的截距小于经过aa的截距.

定理22: bb不可能成为答案.

  • kk表示直线line1line1的斜率
  • ba=yakxa,bb=ybkxb,bc=yckxcb_a = y_a - k \cdot x_a,b_b = y_b - k \cdot x_b,b_c = y_c - k \cdot x_c
  • ba,bb,bcb_a,b_b,b_c分别表示直线line1line1经过点a,b,ca,b,c时的截距.

那么现在只需要证明:babbbcbbb_a \leqslant b_b \lor b_c \leqslant b_b的恒成立.

根据推论1,分情况讨论:

  1. k<k2<k1k < k_2 < k_1,此时ba<bbb_a < b_b.
  2. k2<k<k1k_2 < k < k_1,此时bc<bbb_c < b_b.
  3. k3<k1<kk_3 < k_1 < k,此时bc<bbb_c < b_b.

所以无论kk的值是哪种情况,bb都不可能成为答案.

推论22: 可能为答案的点集形成下凸壳

在后选点集(例如figure_2)里排除不可能点后形成一个kk单调增加的序列,也就是下凸壳.

figure_5

反证法: 假设kk不是单调增加的,那么存在一对相邻的ki>ki+1k_i > k_{i+1},根据定理22,中间点ai+1a_{i+1}不可能成为答案,与前提排除所有不可能点矛盾.

推论33: 第一个ki>kk_i>k的起点就是最小截距

当直线ll的斜率为kk的时,经过下凸壳的哪个点时截距最小?

所有ki<kk_i < k总是终点较优,所有ki>kk_i > k总是起点较优.又因为下凸壳上的kik_i在递增. 所以直线ll经过第一个ki>kk_i>k的起点时得到最小截距.如果不存 在ki>kk_i>k,那么最后一个点就是最小截距.

入门: 玩具装箱

题目地址: [ luogu P3195: [HNOI2008] 玩具装箱]

解析

根据题目的意思可以很轻松的写出状态转移方程

dp[i]=minj<i{dp[j]+(sum[i]+isum[j]jL1)2} \begin{equation} dp[i] = \min\limits_{j < i}\{dp[j] + (sum[i] +i - sum[j]-j-L-1)^2 \} \tag 1 \end{equation}

其中,sum[i]=1iCksum[i] = \sum\limits_{1}^{i}{C_k},也就是前缀和.显然如果直接按这个方程来做,复杂度为O(n2)O(n^2)

使用 斜率优化

发现公式(1)(1)是一个关于两个变量i,ji,j二元公式.其中变化的只有jj,如果我们可以把是的变化拆分成两个部分(X(j),Y(j))(X(j),Y(j)),那么j[1,i1]j \in [1,i-1]的每一次变化都会产生一对点,这些点都分布在平面上.

且我们想到得到的值是:min{kX(j)+Y(j)}min\{k \cdot X(j) + Y(j)\},kk为定值,那不就是求斜率为kk的直线经过那对点可以得到小截距吗?那么问题就为上面斜率问题.

k(i)=sum[i]+iL1X(j)=sum[j]+j\begin{aligned} k(i) &= sum[i] + i - L -1 \\ X(j) &= sum[j] + j \end{aligned}

则可以得到

dp[i]=min{dp[j]+(k(i)X(j))2}=min{dp[j]+k(i)22k(i)X(j)+X(j)2}=min{2k(i)X(j)+dp[j]+X(j)2+k(i)2}\begin{aligned} dp[i] &= \min\{dp[j]+(k(i) - X(j)) ^2\} \\ &= \min\{dp[j] + k(i)^2 - 2\cdot k(i) \cdot X(j) + X(j)^2\} \\ &= \min\{\fcolorbox{red}{aqua}{$ - 2\cdot k(i) \cdot X(j) + dp[j] + X(j)^2$} + k(i)^2\} \end{aligned}

再设

Y(j)=dp[j]+X(j)2\begin{aligned} Y(j) \quad &= \quad dp[j] + X(j)^2 \end{aligned}

因为k(i)k(i)是定值,所以可以把k(i)2k(i)^2移出来,则得到

dp[i]=min{2k(i)X(j)+Y(j)}+k(i)2dp[i] = \min\{\fcolorbox{red}{aqua}{$ - 2\cdot k(i) \cdot X(j) + Y(j) $}\} + k(i)^2

我们注意到\fcolorbox{red}{aqua}{$- 2\cdot k(i) \cdot X(j) + Y(j) $}形如z = kx+y, 我们设直线l(j)表示为:

l(j)=2k(i)X(j)+Y(j)l(j) = -2 k(i)\cdot X(j) + Y(j)

于是就得到

dp[i]=min{l(j)}+k(i)2dp[i] = \min\{\fcolorbox{red}{aqua}{$ l( j ) $}\} + k(i)^2

显然我们要求的是\min\{l(j)\}, 1 \leqslant j < i,这个公式表示的意思就是: 我们要求直线方程线性规划l(j)l(j)的最小值

定义域为j[1,i)j \in [1,i)之间形成的点集P:{(X(1),Y(1)),(X(2),Y(2)),}P:\{(X(1),Y(1)), (X(2),Y(2)), \cdots \}

对于点集PP中的每一个点pp,都会有一条斜率为k(i)k(i)的直线经过pp,直线上的点 代入公式kx+yk \cdot x + y的值一样 ,而它们的值就是截距

所以我们只需要找到最小的截距

同时,基于上面的公式,我们可以知道以下事实:

  • k(i)k(i)值为正值,且随着ii单调增加

证明 需要维护一个凸包

凸包上的哪个点是答案

凸包上的如何添加点

所以

我们需要维护一个下凸壳

且壳上的点斜率递增

  1. 在壳上找到最优点
  2. 在壳上添加新的点

更一般的公式推断

我们有一个这样的状态转移方程

dp[i]=minj[l,r]{d(j)+B(i)+X(j)k(i)}dp[i]=\min\limits_{j\in[l,r]}\{d(j)+B(i)+X(j) \cdot k(i)\}
  • X(j)k(i)X(j) \cdot k(i) 表示既与ii有关又与jj有关的项,因为ii是固定的,通常X(i)X(i)的值也是定值
  • d(j)d(j) 表示只与jj有关的项
  • B(i)B(i) 表示只与ii有关的项,因为ii是固定的,通常这个项的值也是定值

这样就可以看成这样的一条直线的公式

 ljy=k(i)x+d(j)\colorbox{aqua}{ $ l_j \Rarr y = k(i) \cdot x + d(j) $}

那可以把原式子写成

\begin{equation} dp[i]=\min\limits_{j\in[l,r]}{\colorbox{aqua}{ lj(k(i))l_j(k(i) ) } }+d(i) \end{equation}

所以对于每一个状态ii,可以得到对应的k(i)k(i),那么根据ljl_j就得到了对的值

也就是ljl_j这条直线的线性规划

对于本题来说

\begin{equation} dp[i]=\min\limits_{j\in[l,r]}{\colorbox{aqua}{ lj(k(i))l_j(k(i) ) } }+d(i) \end{equation}

X(j) 是 K(i) 是

为什么我们需要维护一个下凸壳

? 那么第一个满足条件的P值 如何求解最值,找到第一个斜率大于k(i)k(i)的点

为什么要维护一个单调队列

单调队列如何添加点

如何得到头(update)

TODO

dp[0]应该是什么值?

方法2 : 推理法

TODO

我需要使用asymoto 画图 所以需要 asymoto的笔记

代码1: 朴素

#include <ios>

代码2: 模块

参考