学习笔记——斜率优化dp

注:文中全部图片均为手绘,不喜勿喷

总论

斜率优化是dp优化中极其常用的一种手法

第一点,先要懂什么是凸包与单调队列

先来看看凸多边形是什么样

接着再是斜率及斜率优化

一、凸包及凸多边形

凸多边形

就像这样

学习笔记——斜率优化dp_第1张图片

这就不是

学习笔记——斜率优化dp_第2张图片

即所有角都 ≤ 180 \leq180 180°

凸包

一条折线,满足斜率(定义看下面)单调递增或递减,例如

学习笔记——斜率优化dp_第3张图片

二、 单调队列

请看下图
学习笔记——斜率优化dp_第4张图片

三、斜率

进入正题

什么是斜率?

严谨一点讲:

斜率 k = Δ y Δ x k=\frac{\Delta y}{\Delta x} k=ΔxΔy

其中, Δ x \Delta x Δx Δ y \Delta y Δy 表示横坐标差与纵坐标差

Δ x \Delta x Δx 为 0 的时候,即该直线与 y y y 轴平行,该直线斜率不存在或认为趋向于 ∞

一次函数中, f ( x ) = a x + b f(x)=ax+b f(x)=ax+b,a就是其函数影像的斜率

一篇博客少不了一道题

例题——斜率

输入格式

第一行两个整数 n n n m m m

接下来 n n n 行,每行两个整数,表示一个点的坐标。

接下来 m m m 行,每行一个整数,表示一条直线的斜率。

输出格式
对于每个斜率 k k k ,输出 k x + y kx+y kx+y 的最大值, 其中 ( x , y ) (x,y) (x,y) 是给出的 n n n 个点中的一个。

样例

输入

5 4
-1 1
1 2
3 4
4 3
5 6
-2
3
-5
10

输出

3
21
6
56

数据范围与提示

n , m n,m n,m 的范围 [ 1 , 1 0 5 ] [1,10^5] [1,105]; x , y , k x,y,k x,y,k 的范围 [ − 1 0 9 , 1 0 9 ] [-10^9,10^9] [109,109]

思路

一看这题的数据范围,暴力绝对挂,必须考虑优化

首先,暴力的思想是:
a n s = max ⁡ { x i k + y i } ( 1 ≤ i ≤ n ) ans=\max\{x_ik+y_i\}(1\leq i\leq n) ans=max{xik+yi}(1in)
我们考虑舍去多余的判断

不妨先将节点按x轴排序

( x j , y j ) (x_j,y_j) (xj,yj) ( x i , y i )   ( i < j ) (x_i,y_i)~(i(xi,yi) (i<j) 更优时候,有
k x i + y i < k x j + y j kx_i+y_i< kx_j+y_j kxi+yi<kxj+yj
k ( x j − x i ) > y i − y j k(x_j-x_i)> y_i-y_j k(xjxi)>yiyj
− k < y i − y j x i − x j = k j ↔ i -k<\frac{y_i-y_j}{x_i-x_j}=k_{j\leftrightarrow i} k<xixjyiyj=kji

k x ↔ y k_{x\leftrightarrow y} kxy 表示连接 x x x y y y 的线的斜率

显然,一个点只有比两侧的点更优,才可能是最优决策点

则对于每次询问的 k k k ,若点 i i i 是决策点,一定存在 k i ↔ i − 1 ≥ − k > k i + 1 ↔ i k_{i\leftrightarrow i-1}\geq -k>k_{i+1\leftrightarrow i} kii1k>ki+1i

很明显,后一个的斜率 < < <前一个的斜率,是一个上凸包(如图)

学习笔记——斜率优化dp_第5张图片

这样,我们的目的变为维护一个上凸包,即斜率递减

可以利用类似单调栈的方法:遇到一个点 i i i先将其与队末连线,如果产生了一个下凸包,则删掉队末……直至满足条件。然后加入 i i i点(是类似单调栈哦!与单调栈还是不同的)

均摊复杂度 O ( 1 ) O(1) O(1)(证明:因为每个数都最多加入一次,删除一次)

循环结束后

对于每个询问,如何求出最优解?

不难发现,对于询问的 k k k

k j − 1 ↔ j > − k k_{j-1\leftrightarrow j}>-k kj1j>k,则 j j j一定是 [ 1 , j ] [1,j] [1,j]中的最优决策点

k j − 1 ↔ j ≤ − k k_{j-1\leftrightarrow j}\leq -k kj1jk,则 j j j一定是 [ j , n ] [j,n] [j,n]中的最优决策点

每次二分答案,可做到 O ( n log ⁡ n ) O(n\log n) O(nlogn)

当然,可以利用单指针,将k从小到大排序,离线处理

证明:
因为 k k k越大,其答案斜率越小,可以往更后面处理,理论 O ( n log ⁡ n ) O(n\log n) O(nlogn) O ( n + p ) , p = max ⁡ { k i } ( 1 ≤ i ≤ m ) O(n+p),p=\max\{k_i\}(1\leq i\leq m) O(n+p),p=max{ki}(1im)

对于此题,至少 O ( n log ⁡ n ) O(n\log n) O(nlogn),即快排时间复杂度或计排 + m a p +map +map时间复杂度

二、斜率优化dp

这是斜率的升级版

依然少不了一道题

例题——[SDOI2016] 征途

题目描述

Pine开始了从S地到T地的征途。

从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。

Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。

Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。

帮助Pine求出最小方差是多少。

设方差是v,可以证明, v × m 2 v\times m^2 v×m2是一个整数。为了避免精度误差,输出结果时输出 v × m 2 v\times m^2 v×m2

输入格式

第一行两个数 n、m。

第二行 n 个数,表示 n 段路的长度

输出格式

一个数,最小方差乘以 m 2 m^2 m2 后的值

样例 #1

样例输入 #1

5 2
1 2 5 8 6

样例输出 #1

36

提示

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 10 1 \le n \le 10 1n10

对于 60 % 60\% 60% 的数据, 1 ≤ n ≤ 100 1 \le n \le 100 1n100

对于 $100% $ 的数据, 1 ≤ n ≤ 3000 1 \le n \le 3000 1n3000

保证从 S S S T T T 的总路程不超过 30000 30000 30000

思路

  • 第一步:方差这个东西好玄乎,拆开来!
  • 第二步:欸好像可以滚掉点空间!
  • 第三步:时间不够,斜率来凑

第一步

方差 S = 1 m ∑ i = 1 m ( x i − x ‾ ) 2 \texttt{方差}S=\frac{1}{m}\sum_{i=1}^m(x_i-\overline{x})^2 方差S=m1i=1m(xix)2

可以将 n 2 n^2 n2移至左侧
m 2 S = m ( ∑ i = 1 m x i 2 ) − 2 ( ∑ i = 1 m x i ) 2 + ( ∑ i = 1 m x i ) 2 m^2S=m(\sum_{i=1}^{m}{x_i}^2)-2(\sum^{m}_{i=1}{x_i})^2+(\sum_{i=1}^{m}x_i)^2 m2S=m(i=1mxi2)2(i=1mxi)2+(i=1mxi)2
m 2 S = m ( ∑ i = 1 m x i 2 ) − ( ∑ i = 1 m x i ) 2 m^2S=m(\sum_{i=1}^{m}{x_i}^2)-(\sum_{i=1}^{m}x_i)^2 m2S=m(i=1mxi2)(i=1mxi)2

这就是我们要输出的东西

可以发现,第二项其实是个常数, m m m也可以最后乘

这样,需要维护的东西成了平方和

s i = ∑ j = 1 i x j s_i=\sum_{j=1}^{i}x_j si=j=1ixj

d p dp dp式子就是 d p i , l = min ⁡ { d p j , l − 1 + ( s i − s j ) 2 } ( i < j ) dp_{i,l}=\min\{dp_{j,l-1}+(s_i-s_j)^2\}(idpi,l=min{dpj,l1+(sisj)2}(i<j)

第二步(此步可省略)

可以发现,我们能够不按常理出牌,先枚举 l l l,这样可以滚掉 l l l这一层,但要倒序枚举

伪代码:

for i=1->m:
    for j=n->1:
        for k=1->j-1:
            dp[j]=minimum(dp[j],dp[k]+(s[j]-s[k])^2)

第三步

重中之重到了!!!

我们还要继续拆式子(悲)

( s i − s j ) 2 = ( s j 2 − 2 s j s i ) + s i 2 (s_i-s_j)^2=(s_j^2-2s_js_i)+s_i^2 (sisj)2=(sj22sjsi)+si2

带进 d p dp dp式子内,得
d p i = min ⁡ { d p j + s j 2 − 2 s j s i + s i 2 } dp_i=\min\{dp_j+s_j^2-2s_js_i+s_i^2\} dpi=min{dpj+sj22sjsi+si2}

斜率优化有个套路,就是先提再构

即提出常数项
d p i = min ⁡ { d p j + s j 2 − 2 s j s i } + s i 2 dp_i=\min\{dp_j+s_j^2-2s_js_i\}+s_i^2 dpi=min{dpj+sj22sjsi}+si2

构造一个只与 j j j有关的函数
f ( j ) = d p j + s j 2 f(j)=dp_j+s_j^2 f(j)=dpj+sj2
d p i = min ⁡ { f ( j ) − 2 s j s i } + s i 2 dp_i=\min\{f(j)-2s_js_i\}+s_i^2 dpi=min{f(j)2sjsi}+si2

接着是斜率的老套路

一个 j 1 j_1 j1 j 2 j_2 j2优且 j 2 < j 1 j_2j2<j1,仅当
f ( j 1 ) − 2 s j 1 s i > f ( j 2 ) − 2 s j 2 s i f(j_1)-2s_{j_1}s_i>f(j_2)-2s_{j_2}s_i f(j1)2sj1si>f(j2)2sj2si
f ( j 1 ) − f ( j 2 ) > 2 s i ( j 1 − j 2 ) f(j_1)-f(j_2)>2s_i(j_1-j_2) f(j1)f(j2)>2si(j1j2)
f ( j 1 ) − f ( j 2 ) 2 ( j 1 − j 2 ) < s i \frac{f(j_1)-f(j_2)}{2(j_1-j_2)}2(j1j2)f(j1)f(j2)<si

这样与第一题截然相反,是要维护一个下凸包

但二分还是一样的

理论复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


与官方博文或参考文献对照,可更好理解

参考文献:https://www.luogu.com.cn/blog/aben-blog/xie-shuai-you-hua-dp

最新消息!最近发起活动,请选出其中最小的图片,有奖竞猜!(其实就是把名字写上去)

你可能感兴趣的:(学习,笔记)