幫助——狀壓

幫助


這道題好題,接下來咱們從頭至尾詳細地分析一遍這道題的作法以及給咱們之後作題目的啓發。數組


考慮到\(25\)\(32\)這一值域很小,而且能夠總體平移到\(0\)\(7\),這是原始想法。優化


接下來積累一個比較好的想法:將一個數抽出來再放回去至關於僅僅把抽出來的數一股腦取出來,最後再進行插入操做spa

該轉化有何好處呢?get

  1. 能夠將複雜的問題分步解決;2. 轉化爲較爲通用的問題:也即,咱們將原問題轉化爲了從一個序列刪一些數,再加一些數求最值。

該轉化能夠被普遍地應用。class

回到本道題,咱們能夠將問題視做:先從這一堆數中取走若干個數,再將這若干個數插回去,在該過程當中,若是取出的一些在數值上相等,按照貪心來說,插入回去的時候一定在一塊兒,由於這樣最優。統計


有了這樣的想法,咱們不妨定義狀態:總結

\[dp(i,j,0/1) \]

分別表明前\(i\)個數,還剩\(j\)次操做能使用,是否被取走的最小混亂度。數據

接着咱們轉移,發現:集合

  1. 誒?若是咱們選擇取走,那麼直接轉移,可是最小混亂度還須要加上咱們取走的數從新加入原序列中形成的混亂度;
  2. 那若咱們不取走,就會發現若上一個數選擇取走,咱們整個狀態轉移沒辦法進行。

所以,咱們不難想到能夠更加細緻化狀態。di


再考慮數據範圍,誒?\(1\)~\(8\)?這麼小。

咱們能夠給原來的狀態加一個維度.

\[dp(i,j,S) \]

其中\(S\)表明包括\(i\)在內前面被取走數的集合。

那麼咱們有:

\[dp(i+1,j+1,S\cup\{a_{i+1}\})=min(dp(i,j,S))\\dp(i+1,j,S)=min(dp(i,j,S))+w \]

第一個方程很容易理解,而第二個方程中的\(w\)是啥?

咱們考慮,當\(a_{i+1}\)\(a_i\)數值相同時,\(w\)就等於\(0\),若是不相同,\(w\)就等於\(1\)

且慢

若是\(a_i\)這個數被取走了呢???咱們便不是這麼好辦了。

於是,咱們須要再加一維進行描述。

因此,咱們能這樣嗎:

\[dp(i,j,S,0/1) \]

集百家之所短

它的問題出在了咱們沒辦法直接肯定上一個保留的數是否與之相等。

那麼,咱們這樣唄:

\[dp(i,j,S,pre) \]

\(pre\)表明上一個被保留的數的位置。

已經能夠搞了。


\[dp(i+1,j+1,S\cup\{a_{i+1}\},pre)=min(dp(i,j,S,pre))\\dp(i+1,j,S,i+1)=min(dp(i,j,S,pre))+(if\ (a_{pre}\not=a_{i+1})1;\ else\ 0) \]

那麼,這個式子就能夠經過了嗎?別忘了滾動數組啦。

那最終答案怎麼表示呢?

好問題,不太好解決——保留的數的混亂度加上取走的數從新排隊的混亂度,咱們記錄的集合\(S\)好像不能記錄保留的數中有與之相等的數。由於若是原序列中有相等的數,那麼取出來的數最優的狀況是和該數接在一塊兒生活。

第二個思想:補集轉化。

既然咱們知道取出來的數集合做爲狀態的一維不利於統計答案,那麼咱們可不可使保留的數做爲狀態的一維?

這是能夠實現的。而且答案就是全部數值的集合減去未被取出來的數值集合剩下的數各成一峯。

總的時間複雜度爲:\(O(n^2*k*2^7)\),卡一卡常就過了。


其實進一步優化:

考慮到咱們最後那一維其根本咱們是來解決上一個未取出的數的數值是否與當前不取出的數相等。

由於數的值域那麼小,咱們僅記錄上一個數的數值是多少便可。\(O(n*k*2^{11})\)


咱們總結一下:

  1. 咱們考慮到原問題的值域較小,所以咱們平移該值域;
  2. 將取出一個數再放回去的動做轉化;
  3. 將狀態精細化,這也是DP常見的作法;
  4. 補集轉化思想,將取出來轉化爲不取出來;
  5. 狀態精簡。

這個問題就這樣迎刃而解了。

相關文章
相關標籤/搜索