斜率优化dp

算法介绍

使用条件

形如 d p [ i ] = m i n { A ( i ) × B ( j ) + C ( i ) + D ( j ) } dp[i]=min\{A(i)\times B(j)+C(i)+D(j)\} dp[i]=min{A(i)×B(j)+C(i)+D(j)}的转移方程可尝试使用斜率优化。
(取 m a x max max是类似的,本文不赘述)

法一:线性规划

考虑把 d p [ i ] = A ( i ) × B ( j ) + C ( i ) + D ( j ) dp[i]=A(i)\times B(j)+C(i)+D(j) dp[i]=A(i)×B(j)+C(i)+D(j) 化成 y = k x + b y=kx+b y=kx+b的形式,其中 y , x y,x y,x只与 j j j有关, k , b k,b k,b只与 i i i有关,且 x x x严格单调递增

则有:
D ( j ) = − A ( i ) × B ( j ) + d p [ i ] − C ( i ) D(j)=-A(i)\times B(j)+dp[i]-C(i) D(j)=A(i)×B(j)+dp[i]C(i)
其中 y = D ( j ) , k = − A ( i ) , x = B ( j ) , b = d p [ i ] − C ( i ) y=D(j),k=-A(i),x=B(j),b=dp[i]-C(i) y=D(j),k=A(i),x=B(j),b=dp[i]C(i)

在平面直角坐标系上把所有的 ( x j , y j ) (x_j,y_j) (xj,yj)(即 ( B ( j ) , D ( j ) ) (B(j),D(j)) (B(j),D(j)))标出来。
要令 d p [ i ] dp[i] dp[i]最小,则要令 b b b最小,即是要找到某一点 ( x j , y j ) (x_j,y_j) (xj,yj),使斜率为 k k k的直线经过该点时算出来的 b b b最小。
发现只有 在给出点的下凸壳上的点可能成为最优决策点。
在这里插入图片描述

法二:代数法(数形结合)

j 1 , j 2 j_1,j_2 j1,j2 ( 0 ≤ j 1 < j 2 < i ) (0\leq j_1<j_2<i) (0j1<j2<i) d p [ i ] dp[i] dp[i]的两个决策点,且决策点 j 2 j_2 j2优于 j 1 j_1 j1,则有:
A ( i ) × B ( j 2 ) + C ( i ) + D ( j 2 ) ≤ A ( i ) × B ( j 1 ) + C ( i ) + D ( j 1 ) A(i)\times B(j_2)+C(i)+D(j_2)\leq A(i)\times B(j_1)+C(i)+D(j_1) A(i)×B(j2)+C(i)+D(j2)A(i)×B(j1)+C(i)+D(j1)

化简式子,使不等号左边只与 i i i有关,不等号右边只与 j 1 , j 2 j_1,j_2 j1,j2有关:
A ( i ) ≤ − D ( j 2 ) − D ( j 1 ) B ( j 2 ) − B ( j 1 ) A(i)\leq -\frac{D(j_2)-D(j_1)}{B(j_2)-B(j_1)} A(i)B(j2)B(j1)D(j2)D(j1)
− A ( i ) ≥ D ( j 2 ) − D ( j 1 ) B ( j 2 ) − B ( j 1 ) -A(i)\geq \frac{D(j_2)-D(j_1)}{B(j_2)-B(j_1)} A(i)B(j2)B(j1)D(j2)D(j1)
x j = B ( j ) , y j = D ( j ) x_j=B(j),y_j=D(j) xj=B(j),yj=D(j),则 D ( j 2 ) − D ( j 1 ) B ( j 2 ) − B ( j 1 ) \frac{D(j_2)-D(j_1)}{B(j_2)-B(j_1)} B(j2)B(j1)D(j2)D(j1)可以看作 P j 1 ( x j 1 , y j 1 ) P_{j_1}(x_{j_1},y_{j_1}) Pj1(xj1,yj1), P j 2 ( x j 2 , y j 2 ) P_{j_2}(x_{j_2},y_{j_2}) Pj2(xj2,yj2)两点连线的斜率。

也就是说,如果存在两个决策点 j 1 , j 2 j_1,j_2 j1,j2满足 0 ≤ j 1 < j 2 < i 0\leq j_1<j_2<i 0j1<j2<i,使得 P j 1 P_{j_1} Pj1, P j 2 P_{j_2} Pj2两点连线的斜率 ≤ − A ( i ) \leq -A(i) A(i),那么决策点 j 2 j_2 j2优于 j 1 j_1 j1

在这里插入图片描述
于是,对于这样子的三个点,可证 B B B一定不是最优决策点

我们可以将 B B B从候选决策点中踢出去(删除),只留下 A A A C C C,删后的情况如下图所示:
在这里插入图片描述
最终,我们维护的候选决策点应该构成了一个下凸壳:
在这里插入图片描述

实现

x j x_j xj的单调性分类

  1. x j x_j xj递增(递减的话给 x x x取个负就是递增了):单调队列维护凸包
  2. x j x_j xj不单调:平衡树维护凸包/cdq分治提供单调性

k i k_i ki的单调性分类

  1. k i k_i ki递增: 只需要维护部分凸包。即用单调队列维护凸包时可以不断弹掉队首,删掉不需要维护的凸包;查询答案时直接取队首即可。
  2. k i k_i ki不递增:必须维护完整凸包。即用单调队列维护凸包时不能再弹掉队首了(即用单调栈维护凸包);查询答案时二分找最优决策点。

实现细节

  1. x j x_j xj 非严格递增时,在求斜率时可能会出现 x j 1 = x j 2 x_{j1}=x_{j2} xj1=xj2 的情况,此时最好写成这样的形式:return Y(j)>=Y(i)?inf:-inf,而不要直接返回 i n f inf inf 或者 − i n f −inf inf
  2. 手写队列的初始化是 h=1,t=0,由于队列初始化大多都要塞入一个点 P ( 0 ) P(0) P(0),所以在一些题解中可以看到h=t=1
  3. 手写队列判断不为空的条件是h<=t,而出入队判断都需要有至少 2 两个元素才能进行操作。所以应是 h<t
  4. 计算斜率可能会因为向下取整而出现误差,所以 s l o p e slope slope 函数最好设为 l o n g d o u b l e long double longdouble 类型。
  5. 在比较两个斜率时,尽量写上等于,即<=>= 而不是<>。这样写对于去重有奇效(有重点时会导致斜率分母出锅),但不要以为这样就可以完全去重,因为要考虑的情况可能会非常复杂,所以还是推荐加上 1. 中提到的特判,确保万无一失。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值