1. 程式人生 > 實用技巧 >MSP430G2ET時鐘系統

MSP430G2ET時鐘系統

莫隊是莫濤大佬提出的演算法。

建議參閱:http://oi-wiki.com/misc/mo-algo/


0x00 前置知識

1 分塊(根號演算法)

2 sort與運算子過載

0x01 演算法思想

例題:給你一個數列 \(a_i\), 對於每個\(l\)\(r\) , 輸出\([l,r]\)中有多少種數 。

怎麼做呢?不會

演算法1:\(cnt_i\) 記錄 \(i\) 出現的次數,遍歷\(a_l\)\(a_r\)\(++cnt_{a_i}\) ,最後掃描一遍,用\(ans\)計算多少個\(cnt\)不等於\(0\)

這種做法,對於單個區間還挺好,對於多個區間就涼了(\(O(n^2)\))。

怎麼優化呢?

我們可以考慮利用之前的\(ans\)

比如下面的栗子:

比如現在知道\([l_1,r_1]\)的結果,要求\([l_2,r_2]\)的結果。

現將\(l\)往右移一位……哦少了一個\(1\)!!!

\(--cnt_{1}\)

再比如將\(r\)向右移……多了一個\(1\)

\(++cnt_{1}\)

於是:

演算法2:先得到一個區間的答案,再一步一步挪左右指標。

多好!

每次移動只有\(O(n)\)……欸那不還是\(O(n^2)\)

但我就是覺得這演算法很好,所以要優化。

所以移動指標的次數要減小。

什麼好辦法呢?

分塊!

莫隊

我們考慮講區間分塊,然後對於每個區間,以區間右端為關鍵字由小至大排序。

這樣子對於每個塊內,右端點會一直往右移。複雜度是 \(O(n)\)

然後如果從一個塊移到另一個塊,也是右端點一路向左退,也是 \(O(n)\) 的。

所以複雜度是 \(O(n \sqrt n)\)

這時候有的小朋友就要問了:

吶,為什麼不把它們都一起排序呢?✰」

問得好!

如果這樣,來康康我們的左端點君。

它有可能會從不停地從左往右移動,再從右往左……這樣複雜度退化成 \(O(n^2)\) 了。資料可以卡。

如果分塊的話,可以對整個數列適當地打亂,不容易被卡。

沒啦。

0x02 參考資料

https://www.cnblogs.com/WAMonster/p/10118934.html

http://oi-wiki.com/misc/mo-algo/