演算法學習筆記(23):杜教篩

Qerrj發表於2024-06-07

杜教篩

參考來源: 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)\) 時:

  1. 可以快速計算 \(\sum_{i=1}^n(f * g)(i)\)
  2. 可以快速計算 g 的字首和,以用數論分塊求解 \(\sum_{i=2}^ng(i)S\left(\left\lfloor\dfrac{n}{i}\right\rfloor\right)\)

則我們可以在較短時間內求得 \(g(1)S(n)\)

例題

相關文章