注:文中全部图片均为手绘,不喜勿喷
斜率优化是dp优化中极其常用的一种手法
第一点,先要懂什么是凸包与单调队列
先来看看凸多边形是什么样
接着再是斜率及斜率优化
就像这样
这就不是
即所有角都 ≤ 180 \leq180 ≤180°
一条折线,满足斜率(定义看下面)单调递增或递减,例如
进入正题
什么是斜率?
严谨一点讲:
斜率 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}(1≤i≤n)
我们考虑舍去多余的判断
不妨先将节点按x轴排序
当 ( x j , y j ) (x_j,y_j) (xj,yj) 比 ( x i , y i ) ( i < j ) (x_i,y_i)~(i
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(xj−xi)>yi−yj
− 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<xi−xjyi−yj=kj↔i
k x ↔ y k_{x\leftrightarrow y} kx↔y 表示连接 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} ki↔i−1≥−k>ki+1↔i
很明显,后一个的斜率 < < <前一个的斜率,是一个上凸包(如图)
这样,我们的目的变为维护一个上凸包,即斜率递减
可以利用类似单调栈的方法:遇到一个点 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 kj−1↔j>−k,则 j j j一定是 [ 1 , j ] [1,j] [1,j]中的最优决策点
当 k j − 1 ↔ j ≤ − k k_{j-1\leftrightarrow j}\leq -k kj−1↔j≤−k,则 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}(1≤i≤m)
对于此题,至少 O ( n log n ) O(n\log n) O(nlogn),即快排时间复杂度或计排 + m a p +map +map时间复杂度
这是斜率的升级版
依然少不了一道题
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 后的值
5 2
1 2 5 8 6
36
对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 10 1 \le n \le 10 1≤n≤10
对于 60 % 60\% 60% 的数据, 1 ≤ n ≤ 100 1 \le n \le 100 1≤n≤100
对于 $100% $ 的数据, 1 ≤ n ≤ 3000 1 \le n \le 3000 1≤n≤3000
保证从 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=1∑m(xi−x)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=1∑mxi2)−2(i=1∑mxi)2+(i=1∑mxi)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=1∑mxi2)−(i=1∑mxi)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\}(i
可以发现,我们能够不按常理出牌,先枚举 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 (si−sj)2=(sj2−2sjsi)+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+sj2−2sjsi+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+sj2−2sjsi}+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_2
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(j1−j2)
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)}
这样与第一题截然相反,是要维护一个下凸包
但二分还是一样的
理论复杂度 O ( n log n ) O(n\log n) O(nlogn)
参考文献:https://www.luogu.com.cn/blog/aben-blog/xie-shuai-you-hua-dp
最新消息!最近发起活动,请选出其中最小的图片,有奖竞猜!(其实就是把名字写上去)