淺談斜率優化


斜率優化

如果對於方程形如這樣的

我們不能對其進行比較有效果的優化,因為它的轉移,涉及到了關於i和關於j的一些數組,這時我們就需要用斜率優化了。

通常我們令k<j<i,且用j來更新F[i]比用j優。則有

並且我們都可以化成如下形式,X[j],Y[j]指只關於j的數,X[k],Y[k]亦之

 

我們可以根據這個式子,來優化DP。這大概就是斜率優化的主要思想

實踐出真知,讓我們看一下HDU3507

很容易可以推出狀態轉移方程

 

令k<j<i,那么就可以得到

 

移項可得

如果我們令Y[i]=F[i]+A[i]²,X[i]=A[i],那么可以轉化成如上形式

優化DP

根據剛才的推算,可以發現,要是滿足這個條件的轉移,選j一定比k要優。

我們抽象的把X[i],Y[i]想象成平面上的點,那么這個式子所表示的含義就是兩個點所連成的這條線的斜率。

但是這個斜率又是怎么樣的呢?

我們令g(i,j)表示i點和j點的斜率(上面式子的左邊,k<j<i)。假設g(i,j)<g(j,k)。①如果g(i,j)<F[i](這個F[i]斜率式子右邊的F[i])那么i一定比j優,則j不必選。②如果g(i,j)>F[i],那么j比i優,但是k又比j優,還是不選j。

總結出來,如果g(i,j)<g(j,k),那么j就是廢物,可以T掉。

我們發現,這種情況就是

 

那么最后剩下的圖形,就是一個下凸包殼,也就是斜率單調

優化實現

我們就例題而言

維護一個單調隊列p.get為斜率

表示存的可能為答案的點。因為我們要維護下凸包的性質,必須滿足get(p[tail-1],p[tail])>get(p[tail],i)

我們根據斜率式子,隊首必須滿足get(p[head],p[head+1])<2A[i]

因為斜率越小越優,所以每次選隊首。

大致可以有如下代碼:

while (head<tail) and (get(p[tail-1],p[tail])>get(p[tail],i)) do dec(tail);

加入新增可供轉移的節點

while (head<tail) and (get(p[head],p[head+1])<...) do inc(HeaD)

動態規划轉移

練習題

bzoj1010[HNOI2008]玩具裝箱 

bzoj1096[ZJOI2007]倉庫建設

bzoj1597[USACP2008 Mar]土地購買 

bzoj1911[Apio2010]特別行動隊 

bzoj3156 防御准備 

bzoj3675[Apio2014] 序列分割 

bzoj3437 小P的牧場 

bzoj4518[SDOI2016] 征途 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM