1. 程式人生 > 其它 >斜率優化DP

斜率優化DP

因為SB大佬覺得有用,於是我決定轉載一下洛谷部落格
%%%

優化形如\(f[i]=max/min(a[i]+b[j]+c[i]*d[j])\) \(( j < i )\)的DP方程,其中\(a[i]\) \(c[i]\)為只關於i的函式,\(b[j]\) \(d[j]\)為只關於b的函式,顯然可以化成\(f[i]=max/min(b[j]+c[i]*d[j])+a[i]\) \(( j < i )\)但發現由於存在\(c[i]*d[j]\)與i j都有關的項,所以不能用樸素的單調佇列繼續優化(廢話)

斜率優化

對決策點j,k(j<K)

考慮什麼情況j一定不如k(以min為例)

j不如k即

\(b[j]+c[i]d[j]>b[k]+c[i]d[k]\)

移項

\(c[i] (d[j]-d[k])>b[k]-b[j]\)

\(c[i]>(b[k]-b[j])/(d[j]-d[k])\)(可能會變號,取決於\(d[]\)的單調性)

由於\(c[i]\)單調遞增(題設),可以得到如果當前j不如k,那麼以後j也不會優於k,所以可以捨棄j,想到用單調佇列進行實現

定義函式\(slpoe(j,k)=(b[k]-b[j])/(d[j]-d[k])\)

顯然出隊條件為\(c[i]>slope(q[head],q[head+1])\)(head < tail,head tail這裡是閉區間,開區間+1即可)

如何維護入隊時佇列單調性?

發現,對於佇列中相鄰三項l,m,r,兩個斜率\(a=slope(l,m),b=slope(m,r)\),如果\(a>b\)因為出隊條件\(c[i]>slope(q[head],q[head+1])\)那麼l出隊時,m必然出隊\((c[i]>a>b)\) 所以單調佇列的\(slope\)應該單調遞增

所以x入隊時

$while(head<tail \(&&\)slope(q[tail-1],q[tail])>slope(q[tail],x))$

(畫畫斜率可以發現維護了一個下凸包(也可能是上凸包))

這樣,就可以用單調佇列配上\(slope\)

愉快的砍掉複雜度上一個n

關於數形結合理解,由於本人太菜,顧不做詳細敘述,看看大佬們的部落格吧(逃)

優化後設隊頭為j

\(f[j]=a[i]+b[j]+c[i]d[j]\)

\(-c[i]d[j]+f[i]=a[i]+b[j]\)

可以看做一次函式解析式,-c[i]為斜率,當d[j]=0時,即為f[i],所以直線在y軸上的截距就是所求,要取min,就讓f[i]儘可能小,截距儘可能小,畫圖(本人不會)發現是個下凸包
(具體還是看大佬們的部落格吧。。)

模板

P3628

P2120

P3195

不要少項!不要少項!不要少項!

f[i]的賦值可以直接用最初的式子,不用展開,推的式子寫個slope就行(不要問我為啥要寫這個)