斜率優化是用於優化一些線性dp,主要思想類似於凸包。
下面來看乙個例題:hdu 3507
由題意不難想到是dp,也很容易退出轉移過程f[
i]=m
in(f
[j]+
(s[i
]−s[
j])2
)+m(
i∈[0
,i−1
])但是一看
n 的範圍馬上就萎了,下面來看看用斜率怎麼優化。
現將推出的轉移方程化簡:f[
i]=m
in(f
[j]+
s[i]
2+s[
j]2−
2s[i
]s[j
])+m
顯然s[i
]2對於當前狀態
i 來說是個定值,所以移出來f[
i]=m
in(f
[j]+
s[j]
2−2s
[i]s
[j])
+m+s
[i]2
。 下面來看如何將它看成一條直線 設x
=s[j
],y=
f[j]
+s[j
]2,k
=2s[
i](注
意這裡的
k一定要
和當前狀
態i有關
) 那麼b
=−kx
+y y
=kx+
b mi
n(b)
就是我們要的最小值。
既然已經轉化為直線,那麼就我們就是要拿一條斜率固定的直線在乙個有許多點的平面內尋找交點,
如果要使截距
b 最小,那麼肯定是這條直線肯定與平面的點所形成的的下凸殼相交,
所以在尋找答案的同時我們還要維護乙個下凸殼。
再回到例題中,因為題目中的斜率為2s
[i],是單調遞增的,
對比圖會發現,隨斜率的增長,直線與下凸殼的交點是不斷向
x 軸的正方向移動,
這用乙個指標標記就可以了。
效率顯然是o(n)的。
若跳出這道題去看斜率優化,會出現許多情況。
如果從轉移方程中推出k不滿足遞增,那麼就要二分在下凸殼上尋找。
如果連x
的座標都不能滿足遞增,就需要用資料結構維護下凸殼。
#include
#include
#include
#define ll long long
using
namespace
std;
const
int maxn=500005;
ll s[maxn],f[maxn];
struct jz;
jz operator-(jz &b)
}a[maxn];
int n,m,til,now;
inline
int _read()
ll getb(jz x,ll k)
ll check(jz x,jz y)
int main()
printf("%lld\n",f[n]);
}return
0;}
斜率優化總結
考慮如下 dp dp i max min a i b j c i d j j i 其中,a i c i 只與i有關,b j d j 只與j有關。括號裡有與i,j同時有關的項,導致單調佇列優化失效,但是如果這樣的項只有乙個可以採用斜率優化。方法如下 將此dp方程轉化為 dp i a i max min...
斜率優化總結
題目 luogu p2365 任務安排 題解 題解 p2365 任務安排 對於此類方程 f i begin f j val i,j end 暫時忽略min和範圍得 f i f j val i,j 整理得 f j val i,j f i 令 val i,j f i g j h i 則 f j f i ...
斜率優化總結
首先,推薦乙個大佬的部落格,講解非常詳細,所以不會斜率優化的請移步這裡,本部落格主要講題目分析qwq 主要講解題目 1.hnoi2008玩具裝箱 2.zjoi2007倉庫建設 3.usaco08mar土地徵用land acquisition 4.apio2010特別行動隊 下面,開始吧。題目分析 如...