題意
有 \(n\) 個數 , 每次可以合併相鄰兩個數為一個數 , 新的數的值是原來兩個數的和 .
求最小操作次數 , 使得序列變為不降序列 .
\(case 1: n \le 3000\)
\(case 2: n \le 1e5\)
題解
做法一
一本通上給到的一種做法 .
首先設計狀態 \(f_{i,j}\) 當前位置 \(i\) , 上一次轉移位置 \(j\) , 存最小操作次數 . 直接更新 :
其中要滿足 \(i\) 到 \(j+1\) 的和不小於 \(k+1\) 到 \(j\) 的 .
顯然所有可以取的 \(k\) 是一個字尾 , 因此直接記錄字尾 \(\max\) , 就可以實現 \(O(1)\) 單次轉移 . 可以用二分找到 \(k\) 的位置 .
不過 , 因為在 \(j\) 增大的過程中 , \(k\) 的位置相應地不減 , 所以可以用指標掃一遍 ,總複雜度 $O(n^2) $.
做法二
從剛才的做法可以得到一個觀察 , 即在 \(j\) 儘量大且滿足有方案的時候 , 由 \(j\) 向後貢獻總是最優的.
具體地 :
對於有方案的所有 \(f_{i,j}\) , 最大的 \(j\) 向後更新的次數總比前面的多 . 這一點可以由剛才的單調性證明 .
因為最少操作次數相當於更多的轉移次數 , 透過歸納法可以發現最大的 \(j\) 總有最小的操作次數 .
這一點其實可以直接觀察得到 . 這樣就得到了一個很強的 , 貪心性質的結論 .
這啟發我們透過 dp 只計算到每一個位置最大的末尾數字 , 每次更新儘量取最大的 \(j\) , 滿足 \(\sum^{i}_{k=j+1} \le f_j\) .
可以透過平衡樹或線段樹維護貪心過程 , 複雜度 \(O(n\log n)\) .
總結
題目本身並不難 . 找性質的過程還是很容易的 , 不管是透過觀察直接 dp 的更新過程 , 還是直接模擬過程找規律 , 都能體會到一種很強的 **" 單調性結論 " ** .
具有單調性的問題常常可以從單調的角度 , 之抓住對結果最有用的部分 , 最佳化掉沒有必要考慮的部分 , 比如單調棧 , 單調佇列 . 更廣義地看 , 例如在笛卡爾樹上 , 這種方法在貪心 , 以及找性質都有一種體現 . 找性質時明確自己的目的 , 也許對於快速發現性質是有用的 .