Slope trick優化dp


適用於一類dp值關於下標的函數是連續函數,分段函數,凸函數,每一段需要是一次函數,需要是整數斜率。常見於一些最小調整代價題,因為經常會有\(|x-y|\)這種典型符合上述要求的函數出現,而且這類dp通常會有對應下標相加的形式出現。
我們考慮通過最右一段的一次函數\(y=kx+b\),和前面的分界點來表示這個函數。要求相鄰段之間函數的斜率差為\(1\),也就是說如果真正的函數里有相鄰兩段之間斜率差不為\(1\)的話,這個分界點要在數據結構里出現多次。比如下面這個函數:

\[f(x)=\begin{cases}-x&x<-1\\1&-1\leq x<1\\2x-1&x\geq 1\end{cases} \]

那我們需要維護一個最右段函數\(k=2,b=-1\),和一個分界點集合\(S=\{-1,1,1\}\)
兩個滿足條件的函數相加的話,就是最右段函數相加,分界點集合取並。因為都是連續函數,只要維護的斜率是對的,函數值就肯定就是對的。
但是你可以發現維護最右段函數並不重要,分界點集合才重要。所以說最右段函數只是其中一種維護方式。通過幾道題來用一下。

CF713C
首先嚴格遞增這個事很煩,把他轉化成單調不降,就是令\(a_i-=i\)。然后暴力dp就很顯然了。令值域為\(m\)
\(dp(i,j)=\min\limits_{k=1}^jdp(i-1,k) +|a_i-j|\)
用函數來代替這個\(dp\)的第二維\(f_i(x)=dp(i,x)\)。設函數\(g_i(x)\)\(dp(i,j)\)第二維的前綴最小值對應的函數。那么有
\(f_i(x)=g_i(x)+|x-a_i|\)
考慮用維護最右段函數的方式維護\(f\)\(g\)。一個下凸函數取前綴最小值的話,相當於是把斜率為\(0\)后面的段全部去掉,變成和這段一樣。這個\(h(x)=|x-a_i|\)是一個很簡單的函數,他的最右段函數就是\(x-a_i\),分界點集合就是\(\{a_i,a_i\}\)。用一個優先隊列維護即可,復雜度\(O(n\log n)\)
回顧一下剛才的過程,實際上slope trick優化dp大多數就是轉移時構造一個\(g_i(x)\)替代那一坨\(min\),把轉移方程轉化為對應下標相加的形式。用維護最右段函數來表示這個函數的優勢實際上在於這個構造出來的函數如果是前綴最小值的話,非常容易維護。同樣的,如果是后綴最小值,可以考慮維護最左段函數。

CF1534G
推性質部分見我的置頂博客去Ctrl+F。快進到優化dp部分。還有,這個dp需要整數定義域是一段連續區間,否則不能維護。那么這個題可以通過倒着設狀態來規避dp值里有正無窮的問題。

\[dp(i,j)=\min\limits_{t=j}^{j+\Delta i}dp(i',t)+\sum|j-x'| \]

這里的\(\Delta i\)\(i'\)\(x'\)對於固定的\(i\)都是固定的,不用管。第二個\(\sum\)號暴力枚舉復雜度是對的。
\(f_i(x)=dp(i,j),g_i(x)=\min\limits_{t=x}^{x+\Delta i}f_i(t)\)
那么有

\[f_i(x)=g_{i'}(x)+\sum|x-x'| \]

這個\(g_i(x)\)形式不太好看,由於他不是前綴min也不是后綴min,影響到的東西比較多。但是他是一段包含自己的區間,對於一個下凸函數,\(x\)下標函數值變成一段包含自己區間的函數值最小值是很有規律的。我們可以考慮維護中間斜率為\(0\)的一段的截距\(y=b\)。設中間那段區間為\([L,R]\)(分段連續函數開區間閉區間不重要)。
那么對於\(x\geq L\)的部分,函數值顯然沒有變化。對於左邊,相當於把這段區間拉長為\([L-\Delta i,R]\)\(L\)左邊的部分整體平移到\(L-\Delta i\)左邊。所以用一個大根堆,一個小根堆分別維護兩側的分界點集合,對於一次從\(f_i(x)\)變成\(g_i(x)\),把左側的堆整體打一個標記即可。
往里加一個\(h(x)=|x-v|\)的話,就要對於\(v\)和中間段端點\([L,R]\)大小關系分類討論了。在區間內的話,直接往左插一個\(v\),往右插一個\(v\)。在左邊的話,就插入兩個\(v\),然后把左邊堆頂彈出來插入右邊堆即可。過程有點類似對頂堆。右邊類似。
這么做是利用凸函數區間min的性質。只要維護出來中間段特殊的地方即可。

APIO2016煙花表演
dp是非常顯然的。對於\(u\)的每個兒子\(v\),設\(w\)\((u,v)\)邊權,有\(dp(u,i)+=\min\limits_{t=0}^i\{dp(v,t)+|w-(i-t)|\}\)
這個形式其實就很復雜了。還是設\(f_u(x)=dp(u,x),g_v(x)=\min\limits_{t=0}^i\{f_v(t)+|x-(w+t)|\}\)
雖然形式很復雜,而且沒法把\(x\)和枚舉min的\(t\)拆開。那就整體考慮,但是還是和上一個題一樣,這是個凸函數,只要是一段區間的最小值肯定有很好的性質。這是個前綴的最小值,雖然不是\(f\)的前綴最小值。。所以說就肯定和中間最低的一段\([L,R]\)有關。具體就不展開了,借助都是整數斜率這個性質,自己分類討論手推一下容易得到:

\[g_v(x)=\begin{cases}f_v(x)+w&x\leq L\\f_v(L)+L+w-x&L<x\leq L+w\\f_v(L)&L+w<x\leq R+w\\f_v(R)+x-R-w&x>R+w\end{cases} \]

別管看起來多花里胡哨,別忘了我們只需要維護分界點集合和某一段函數。觀察這個形式發現斜率大於\(0\)的只有一段,那就可以考慮維護最右段函數。只要能把最右段函數維護出來,前面式子根本不用管,就把分界點弄對就行。仔細觀察一下發現\(f_v(R)\)需要把所有斜率大於\(0\)的分界點都彈掉。根據合並的性質,一個函數斜率大於\(0\)的段只有兒子個數個,所以暴力彈就對。分界點集合的話,發現就是刪掉一個\(L\)\(R\),加入一個\(L+w\)\(R+w\)。然后兩個兒子合並的話可以啟發式合並就\(O(n\log^2 n)\)。寫可並堆就少一個\(\log\)


免責聲明!

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



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