標籤:mit 答案 修改 https math code limit rip 部分
hihocoder 1529 不上升序列[斜率最佳化]Description
給出一個序列 \(a[1...n]\) ,求構造一個 \(b[1...n]\) ,滿足\(b_{i+1}\le b_{i}\),使得 \(\sum\limits _{i=1}^{n} |a_i-b_i|\) 最小 .
Solution關於暴力與轉移方程
首先對於暴力轉移,定義\(dp_{i,j}\)為轉移到i點,權值為j的最小花費.
那麼有轉移方程 $dp_{i+1,j}= min(dp_{i,k})+|A_i-j| $ [k>=j]
函數映像及證明
然後分析\(dp_{i,j}\) 構成的函數,定義 \(f(x)=dp_i\) ,那麼可以得到\(f(x)\)是一個下凸函數 [斜率單調不遞減]
首先對於i=1的情況,映像是:
很顯然是一個下凸函數
其中y表示花費,x表示b1的取值,a1表示原來第一個點的值
再觀察上面給出的轉移方程,發現對於一個j,用到的是大於等於自己的k對應的最小值
所以那段下降的函數是無用的
如果要轉移到下一層的話,我們就只用管:
然後加入a2,但考慮a2構成的映像是和上面a1的映像相同的,然後再與修改後的轉移映像相疊加,不難發現映像的斜率單調不減
所要維護的東西
由上面的推導可知:
加入一個數之後,映像會有所改變,並且我們不用管斜率小於等於0的部分函數
所以就始終維護一個斜率大於0且單調遞增函數即可,並且答案就為那個下凹點
假設我們考慮 \(a_i\) ,那麼 \(x< a_i\)的部分的斜率都要 -1,\(x> a_i\)的部分斜率都要 +1
如何維護斜率
加入第一個點後 \(f(x)\) 是一個斜率為1的遞增函數
那麼就放入\(a_1\),表示 \([a_1,\infty]\) 的局部函數斜率都為1
如果加入一個 \(a_2\)
若\(a_2\ge a_1\) ,那麼 \([a_1,a_2]\) 的局部函數斜率變為0 ,\([a_2,\infty]\) 斜率變為2
若\(a_2<a1\) ,那麼 \([a_2,a_1]\) 的局部函數斜率變成1,\([a_1,\infty]\) 的斜率變為2
對於第一種情況,可以看做 \([a1,\infty]\) $\to $ \([a1,a2],[a2,a2],[a2,\infty]\) 分別對應 0,1,2三種斜率
對於第二種情況,可以看做 \([a1,\infty]\) $\to $ \([a2,a1],[a1,\infty]\) 分別對應 1,2兩種斜率
已知斜率小於等於0的函數部分是不要的
所以對於第一種情況,應該把\(a_1\)這個點給刪掉,並加入兩個\(a_2\)
而第二種情況,只需加入\(a_2\)即可
發現每次只需要調用最左邊的點[即最小值],所以用堆維護即可
如何計算答案
發現對於上述第一種情況,整個函數的下凹點改變了,假設原來凹點為\(f(a_1)=y_1\) ,\(,f(a_2)=y_1+k\times (a_2-a_1),k=1\) ,那麼斜率改變後, 凹點位置轉移到\(a_2\),對應 \(f(a_2)\)不變,所以答案增大\(a_2-a_1\)
RT
斜率最佳化dp