前言
- 莫隊算法是一種非常經典優雅的
暴力算法
- 而在莫隊算法中,最值得探討的問題自然而然就是:這個塊的大小到底應該怎么分?
- 有很多 \(OIer\) 將它看成一個玄學問題,
非常有道理,但其實我們是能夠找到規律的。
普通莫隊
- 普通莫隊最佳分塊大小為 \(\sqrt n\) 。
- 為什么?因為暴力分塊的大小為 \(\sqrt n\) ?並不是。
- 那為什么?
- 我們不妨設塊的大小為 \(s\) ,每個塊的詢問次數為 \(q_i\) ,序列長度為 \(n\) ,詢問總次數為 \(m\) 。那么塊的總數就是 \(\frac{n}{s}\) ,對於塊 \(i\) 來說,其復雜度為 \(q_i\cdot s+n\) 。
- 那么總復雜度為 \(\sum_{i=1}^{n/s} q_i\cdot s+n=ms+n\cdot \frac{n}{s}\) 。因為一般 \(n\) 和 \(m\) 都是等數量級的,我們可以大致忽略其大小差異,所以總復雜度變為 \(n\cdot s+n^2\cdot \frac{1}{s}\) 。
- 利用基本不等式可得當 \(n\cdot s=n^2\cdot \frac{1}{s}\) 即 \(s=\sqrt n\) 時,原式有最小值 \(n\sqrt n\) 。
- 這就是普通莫隊算法分塊的大小以及時間復雜度的來歷。
帶修莫隊
- 帶修莫隊最佳分塊大小為 \(n^{\frac{2}{3}}\) ,
可惜我不會證明。- 所以我就僅僅
裝模作樣地分析一番。
-
一開始自學帶修莫隊的時候有一個疑問,為什么要將右端點也分塊?
-
假如右端點不分塊,仍然設塊的大小為 \(s\) ,序列長度為 \(n\) ,詢問總次數為 \(m\) ,修改總次數為 \(k\) 。那么塊的總數還是 \(\frac{n}{s}\) ,此時得到每個塊 \(i\) 的時間復雜度為 \(q_i\cdot s+n+q_i\cdot k\) 。
-
所以總時間復雜度為 \(\sum_{i=1}^{n/s} q_i\cdot s+n+q_i\cdot k=m\cdot s+n\cdot \frac{n}{s}+m\cdot k\) 。此時我們發現最后面的一項始終為定值,無法通過改變塊的大小來改變,所以時間復雜度為 \(O(mk)\) 。
-
如果分塊呢?我們不妨將兩個塊看成一個整體,表示左右端點在這兩個塊里的一種情況。每個整體 \((i,j)\) 的詢問次數為 \(q_{ij}\) 。但此時整體的總數就不是 \(\frac{n}{s}\) ,而是 \(\left(\frac{n}{s}\right)^2\) 了,對於塊 \((i,j)\) 來說,其復雜度為 \(2\times q_{ij}\cdot s+n\) 。
-
所以總時間復雜度為 \(\sum_{i=1}^{(n/s)^2} 2\times q_{ij}\cdot s+n=2\times m\cdot s+n\cdot \frac{n^2}{s^2}\) 。
-
這個時候我們發現每一項都與塊的大小 \(s\) 有關,故可以通過選擇一個恰當的塊的大小來得到最優的時間復雜度。
-
\(Update\:(on\:2021.3.15)\::\) 當時可能是腦子抽了……像普通莫隊一樣直接用基本不等式搞上去就好了。
-
忽略常數並設 \(m=n\) 可得:\(n\cdot s+\frac{n^3}{s^2}\geq \sqrt{\frac{n^4}{s}}\) ,當且僅當 \(n\cdot s=\frac{n^3}{s^2}\Rightarrow s=n^{\frac{2}{3}}\) 時取等。此時 \(\sqrt{\frac{n^4}{s}}=\sqrt{n^{\frac{10}{3}}}=n^{\frac{5}{3}}\) 。
證畢。
——2021年2月18日