杜教篩
參考來源: OI-Wiki, 網上部落格
線性篩可以線上性時間求積性函式字首和, 而杜教篩可以用低於線性時間求解積性函式字首和。
我們考慮 \(S(n)\) 就是積性函式的字首和, 所以我們嘗試構造關於 \(\large S(n)\) 關於 \(\large S(\lfloor \frac{n}{i} \rfloor)\) 的遞推式。
對於任意一個數論函式 g,必滿足:
\(\begin{aligned} \sum_{i=1}^{n}(f * g)(i) & =\sum_{i=1}^{n}\sum_{d \mid i}g(d)f\left(\frac{i}{d}\right) \\ & =\sum_{i=1}^{n}g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \end{aligned} \)
將 \(\large S(n)\) 提出來就可以得到:
\(\begin{aligned} g(1)S(n) & = \sum_{i=1}^n g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) - \sum_{i=2}^n g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \\ & = \sum_{i=1}^n (f * g)(i) - \sum_{i=2}^n g(i)S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \end{aligned} \)
再將 \(g(1)\) 移過去即可得到 \(S(n)\) 的遞推式, 考慮我們可以自己構造 \(g(n)\) 使得計算變快。
當我們構造出這樣的 \(g(n)\) 時:
- 可以快速計算 \(\sum_{i=1}^n(f * g)(i)\);
- 可以快速計算 g 的字首和,以用數論分塊求解 \(\sum_{i=2}^ng(i)S\left(\left\lfloor\dfrac{n}{i}\right\rfloor\right)\)。
則我們可以在較短時間內求得 \(g(1)S(n)\)。