17.1 優化,是在優化什麼?
先把 10.1 的結論搬回來:程式會不會 TLE,由「運算次數隨資料量 n 成長的形狀」決定——認出 O、代入最大的 n、除以 10^9 跟時限比。
所以優化的目標是換形狀,不是修零頭。一個 O(n^2) 的做法在 n = 10^5 要跑 10^{10} 次,就算你把迴圈裡的運算精簡一半,也還有 5 \times 10^9 次——照樣 TLE。真正的出路是把形狀往下換一階:
| n = 10^{12} 時 | 運算次數 | 感受 |
|---|---|---|
| O(n) | 10^{12} | 約一千秒,死當 |
| O(\sqrt{n}) | 10^6 | 眨眼 |
| O(\log n) | 約 40 | 快到測不出來 |
| O(1) | 1 | 一步 |
同一個 n,形狀差一階就是天堂與地獄。本單元的五個例子,每一個都是一次「換形狀」:
- 用數學性質——把整段迴圈換成一條公式(17.2)
- 用陣列儲存資訊——把「每次都重找」換成「查表一步」:mex 函數(17.3)
- 因數成對——把試除範圍砍到 \sqrt{n}:質數判斷(17.4)
- 每輪減半——把逐一刪除換成整輪重建:約瑟夫問題(17.5)
- 一直除以 2 與改變枚舉順序——認識 \log:Odd Divisor 與 A*B*C(17.6、17.7)