我的第一道斜率優化。
就這道題而言,寫出原始的方程:
dp[i] = min
o(n^2)的複雜度肯定超時,要麼優化轉移,要麼重寫方程。
斜率優化的思想就是減少不必要的列舉(即不列舉肯定不會成為決策點的j)。
我們考慮兩個位置p「選擇q比選擇p優」 當且僅當 dp[q]+(sum[i]-sum[q])2+m < dp[p]+(sum[i]-sum[p])2+m
化簡右邊即:
[ (dp[q]+sum2[q])-(dp[p]+sum2[p]) ] / ( sum[q]-sum[p] ) < sum[i]*2
該式可以看成兩個點連線的斜率:( sum[q], dp[q]+sum2[q] ) 與 ( sum[p], dp[p]+sum2[p] ) 兩點。
文字語言就是:「將每個決策位置看成乙個二維座標系下的點,對於兩個決策點,後者比前者優 當且僅當 兩點連線的斜率小於sum[i]*2」
這樣怎麼減少不必要的列舉呢?
可以發現,所有決策點一定是單調不下降的(題中可能出現權值為0,此時有可能出現斜率為正無窮,若m=0,還有可能出現重點,所以計算斜率不要用除法)
上面的b點一定是不會成為最優決策點的,反證法:
如果b成為最優決策點,那麼
2*sum[i]>kab 且 2*sum[i]bc
而顯然kab > kbc ,這樣就推出了2*sum[i]>kab >kbc >2*sum[i],矛盾。
故b不可能成為最優決策點,同理,d也不行,刪掉這些點後,我們剩下的圖形就是乙個下凸的圖形了:
我們維護這樣乙個下凸的圖形到佇列中:
當要查詢i位置的最優決策點時,一直刪除隊首的點,直到隊中的第一條直線的斜率大於2*sum[i]或隊中只有乙個點,此時隊首元素就是最優決策點。
計算完i位置後,要將i位置對應的點加入到佇列中,此時會刪除一些對尾的點,以保持隊中點的下凸性(注意處理重合的點)。
這樣,我們就利用斜率優化掉了很多不必要的列舉,將時間複雜度從o(n^2)降到了o(n)。
1 #include 2view code#define ln(a,b) ((b)-(a))
3#define maxn 500010
45 typedef long
long
lng;67
struct
vector
11 vector( lng x, lng y, int
id ) : x(x), y(y), id(id) {}
12 vector operator-( const vector & b ) const
13 lng operator&( const vector & b ) const
16};
17typedef vector point;
1819
intn, m;
20int
cost[maxn];
21lng sum[maxn];
22lng dp[maxn];
2324
intbeg, end;
25point qu[maxn];
2627
intmain()
3637 dp[0] = 0
;38 qu[beg=end=0] = point( 0, 0, 0
);39
40for( int i=1; i<=n; i++)
50 printf( "
%lld\n
", dp[n] );51}
52 }
HDU3507 斜率優化
r 題意 把n分成任意段 每段中連續 每一段代價 ci m 求總的最小代價 i l作為提醒自己的經驗題,即使再水也要記住坑點 其實是自己被坑的地方 斜率優化裸題 首先定義dp i 表示把前i個處理好的最小代價 dp i min 一看這個轉移就是n 2的,我們來搞成o n 的。h i m sum i ...
hdu3507斜率優化dp
這題 n可能取500000,o n 2 就會超時吧,所有只能優化。注意到這題的動態規劃方程 dp i max dp j sum i sum j 2 m 化簡下得 dp i max dp j sum i 2 sum j 2 2 sum i sum j 無法直接用單調佇列優化,i和j不能分開。假設j比k...
hdu3507 動態規劃 斜率優化
解題報告題目 題目大意 將序列 c n 分成若干段,每段的值為 c i 2 m.求序列的最小值。演算法 動態規劃 斜率優化 思路 看到題目以為數字和亂序,就沒想是動歸而是數論。因為所求的值與段數無關,因此設定dp方程時,不需要為段數設定狀態。設 dp i 表示前i段的最小值 則有 dp i min ...