1. 程式人生 > >「學習筆記」斜率優化

「學習筆記」斜率優化

「HNOI 2008」玩具裝箱TOY

首先O(n2)O(n^2)做法是顯然的,使用字首和然後暴力列舉轉移

dp[0] = 0;
for(int i = 1; i <= n; i ++) {
	dp[i] = 1LL << 62;
	for(int j = 0; j < i; j ++) {
		LL x = i - (j + 1) + s[i] - s[j];
		dp[i] = min(dp[i], dp[j] + (x - L) * (x - L));
	}
}

上面的dp轉移方程為:(s[k]=i=1kc[i]s[k]=\sum_{i=1}^kc[i]

=i=1kc[i] 為字首和)

dp[i]=min(dp[j]+(ijL1+s[i]s[j])2)&ThickSpace;(0j&lt;i)dp[i]=min(dp[j]+(i - j - L - 1 + s[i] - s[j]) ^ 2) \; (0\leq j &lt; i)

把與i,ji,j有關的分別提出來,令ai=s[i]+iL1,bj=s[j]+ja_i=s[i]+i-L-1,b_j=s[j]+j,則:

dp[i]=min(dp[j]+(aibj)2)&ThickSpace;(0j&lt;i)dp[i]=min(dp[j]+(a_i - b_j) ^ 2) \; (0\leq j &lt; i)

假設選了jj轉移,化簡一下:dp[i]=dp[j]+(aibj)2dp[i]=dp[j]+(a_i - b_j) ^ 2

dp[i]=dp[j]+ai2+bj22aibjdp[i]=dp[j]+a_i^2 + b_j^2 -2a_ib_j

j]+ai2+bj22aibj

2aibj+dp[i]ai2=dp[j]+bj22a_ib_j+dp[i]-a_i^2 =dp[j]+ b_j^2

把這看成是kx+b=ykx+b=y的直線形式,則斜率為2ai2a_ix=bjx=b_jy=dp[j]+bj2y=dp[j]+ b_j^2,截距dp[i]ai2dp[i]-a_i^2

也就是說假設我們用jj轉移,y=2aix+by=2a_ix+b這條直線經過點P(bj,dp[j]+bj2)P(b_j,dp[j]+ b_j^2)時,它的斜率+ai2+a_i^2就是dp[i]dp[i]

這樣我們每次選擇一個最優的jj轉移就行了