演算法
考慮 \(\rm{dp}\)
令 \(f_{i, j}\) 表示前 \(i\) 個數中, 分成 \(m\) 組的最小花費
關於轉移, 我們有
其中 \(\rm{Sum}\) 可以字首和預處理, \(\max, \min\) 可以 \(\rm{ST}\) 表預處理
這樣轉移是 \(\mathcal{O} (n ^ 3)\) 的, 考慮最佳化
這裡是一個 \(\rm{trick}\) , 即費用提前計算, 題面中花費 \(i \times w_{sum}\) 轉化成每一次的花費都是 $ \rm{Sum}(i + 1, n)$
將 \(\rm{dp}\) 柿子轉化成 \(dp_i = \min \left[dp_j + Sum(j + 1, n) + \max(j + 1, i) - \min(j + 1, i))\right]\)
複雜度 \(\mathcal{O}(n ^ 2)\) , 考慮最佳化轉移
對於 \(Sum(j + 1, n)\) 是定值, 我們考慮將其提出
方程轉化成 \(dp_i = Sum(j + 1, n) + \min \left[dp_j + \max(j + 1, i) - \min(j + 1, i))\right]\)
我們必須要最佳化轉移
考慮令 \(g_j = dp_j + \max(j + 1, i) - \min(j + 1, i))\) , 維護 \(g_j\) 最小值
這是可以維護的嗎?
考慮線段樹維護 \(g\) ,
對於每一次更新 \(dp_i\)
我們可以在單調棧中找到區間最大值小於 \(a_i\) 最小的 \(j\) , 顯然的, \(j \sim i\) 這一段中, 區間最大值都需要更新
區間最小值同理
於是我們只需要維護區間最值 and 區間加法
程式碼
總結
費用提前計算是一個巧妙的 \(\rm{trick}\)
注意 \(\rm{dp}\) 不能僅僅簡單的省略掉一維, 很有可能會導致正確性出現問題, 這個多練練應該可以解決
對於神秘轉移式子, 考慮多來幾種資料結構維護