1. 程式人生 > >[BZOJ1010][HNOI2008]玩具裝箱

[BZOJ1010][HNOI2008]玩具裝箱

play line 直線 給定 範圍 隊列 得到 編程 由於

題目大意

記將 \(i\)\(j\) 合並的代價為 $ (\sum_{k = i}^j C_k + j - i - L) ^ 2$ 求總代價最小。
方便起見,全文的 \(j\) 的範圍都是 \(j < i\)

解析

顯然我們能有一種樸素的 \(DP\) , 記 \(f[i]\) 表示前 \(i\) 個最小的代價,\(sum[i]\) 表示 \(C_i\) 前綴和,我們有如下轉移 \[f[i] = min\{ f[j] + (sum[j] - sum[i] + j - i +1 - L) ^ 2 \}\]
為了更加簡潔的表達,我們記 \(sum[j] + j\)\(a[i]\)

\(1-L\)\(l\) 則有 \[f[i] = min\{ f[j] + (a[i] - a[j] - l)^2 \}\]
顯然如果我們暴力進行轉移的話,復雜度是 \(O(n^2)\) 的,下面我們利用 \(坐標化\) 的思想,通過 \(斜率優化\) 將復雜度降為 \(O(nlogn)\)
對於我們要求的第 \(i\) 項,\(a[i]\)\(l\) 都是定值,於是原式可以化為
\[f[i] = min\{-2 * a[i] * a[j] + (f[i] + a[j]^2 + 2 * a[j] * l)\} + (a[i] - l)^2\]
移項可以得到\[f[i] - (a[i] - l)^2=min\{-2 * a[i] * a[j] + (f[i] + a[j]^2 + 2 * a[j] * l)\}\]

令z = \(f[i] - (a[i] - l)^2\), \(k = 2 * a[i]\), \(x = a[j]\), \(y = (f[j] + a[j]^2 + 2 * a[j] * l)\),
原式就變成了:
\[z = min\{-k * x + y\}\]
因為要求 \(f[i]\) 最小,那麽 \(z\) 要最小;對於確定的 \(j\), \(x, y\)都是定值, 所以有
\[y = k * x + z\]
因此,我們可以將求解這個問題抽象成求解所有經過 \(x_j, y_j\) 的直線中,截距最小是多少。由於 \(k\) 給定,我們不難發現答案的最優選取是在下凸包上的。由於\(a[i]\)
單調,則 \(k\) 單調,我們可以通過一個隊列維護下凸包,進而降低編程復雜度。

[BZOJ1010][HNOI2008]玩具裝箱