淺淡杜教篩
淺淡杜教篩
狄利克雷卷積
本文的 *
均表示狄利克雷卷積
定義函式 \(f\) 與 \(g\) 狄利克雷卷積後函式的第 \(n\) 項為 \((f*g)(n) = \sum_{d|n}f(d)g(\frac nd)\)
積性函式
如果對於互質的兩數 \(p, q\) 有:\(f(p)f(q) = f(pq)\) ,則認為函式 \(f\) 為積性函式
特別地,如果對於任意兩數 \(p,q\) 有:\(f(p)f(q) = f(pq)\) ,則認為函式 \(f\) 為完全積性函式
常見的積性函式有:
- 元函式 \(\epsilon\) :\(\epsilon (n) = [n = 1]\) (完全積性)
- 恆等函式 \(I\) :\(I(n) = 1\) (完全積性)
- 單位函式 \(id\) :\(id(n) = n\) (完全積性)
- 莫比烏斯函式 \(\mu\)
- 尤拉函式 \(\varphi\) :\(\varphi(n) = \sum_{i = 1} ^ n[\gcd(i, n) = 1]\)
- 約數個數 \(d\) :\(d(n) = \sum_{i = 1} ^ n[i\ |\ n]\)
- 約數和 \(\sigma\) :\(\sigma(n) = \sum_{i = 1}^ni\cdot[i\ |\ n]\)
常見性質有:
- 對於任意函式 \(f\) ,\(f * \epsilon = f\)
- \(\mu * I = \epsilon\)
- \(\varphi * I = id\)
- \(\begin{align*} \frac {\varphi(n)}n = \sum_{d|n} \frac{\mu(d)}d \end{align*}\)
杜教篩
已知 \(f\) 為積性函式,求 \(S(n) = \sum_{i = 1} ^ n f(i)\) ,\(n \le 10^{10}\)
顯然直接做是肯定不行的,考慮構造一個函式 \(g\) ,使得 \(g\) 以及 \(f * g\) 的字首和很好求(可以 \(O(1)\) 求)
找到這樣的函式 \(g\) (一般是上面常見的幾個積性函式或它們的次方),就可以開始推式子了qwq
顯然 \(\frac id\) 的範圍為 \([1,n]\) 所以可以列舉 \(\frac id\) ,用 \(i\) 代替 \(\frac id\) ,可得
\[\begin{align*} \sum_{i = 1} ^ n (f * g)(i) &= \sum_{i = 1} ^ n \sum_{d | i} f(d) g(\frac id) \\ &= \sum_{i = 1} ^ ng(i)\sum_{j = 1} ^ {\lfloor \frac ni\rfloor} f(j) \\ &= \sum_{i = 1} ^ ng(i)S(\lfloor \frac ni\rfloor) \end{align*} \]由於我們要求 \(S(n)\) ,那麼顯然在上面的式子中當 \(i = 1\) 時有一個 \(S(n)\) ,把它分離出來
\[\begin{align*} \sum_{i = 1} ^ n (f * g)(i) &= \sum_{i = 1} ^ ng(i)S(\lfloor \frac ni\rfloor) \\ &= g(1) S(n) + \sum_{i = 2} ^ n g(i)S(\lfloor \frac ni\rfloor) \end{align*} \]於是得出關鍵式子:
\[g(1)S(n) = \sum_{i = 1} ^ n (f * g)(i) - \sum_{i = 2} ^ n g(i)S(\lfloor \frac ni\rfloor) \]可以預處理出 \(M\) 以內的 \(g ,f, f * g\) 的字首和(\(M\) 為線性可接受的值,一般為 \(\sqrt n\)),遞迴求解 \(S(n)\) ,時間複雜度 \(O(n^{\frac 23})\) ,證明不會
大致程式碼結構
inline int sum_g(const int &x) // 求 g(1) + ... + g(x)
{
...
}
inline int sum_fg(const int &x) // 求 (f * g)(1) + .. + (f * g)(x)
{
...
}
inline int sum_f(const int &x) // 求 S(x)
{
if (x <= M) return S[x]; // 預處理的值
if (mp[x]) return mp[x]; // map 記憶化
int ans = sum_fg(x); // 求 f * g 的字首和
for (int l = 2, r; l <= x; l = r + 1) // 注意不要從 1 開始
{
r = x / (x / l); // 整出分塊
int res = sum_g(r) - sum_g(l - 1); // g(l) + .. + g(r)
ans = (ans - res * sum_f(x / l));
}
return mp[x] = ans;
}
當然杜教篩難就難在求合適的 \(g\) ,對於 \(g\) 難求的問題,可以用 min_25 篩或 powerful number 篩,但是我完全不會 /kk ,這個只能請教數論代師HS了。
例題
題意:
已知 \(a, b\) ,求:
\[\sum_{i = a} ^ b \mu(i) \]先求字首和再差分,再根據常用性質 ,\(\mu * I = \epsilon\) ,所以 \(g = I, f * g = \epsilon\) ,直接做
題意:
已知 \(n\) ,求:
\[\sum_{i = 1} ^n \sum_{j = 1} ^n \text{lcm}(i, j) \]推式子:
\[\begin{align*} &\sum_{i = 1} ^n \sum_{j = 1} ^n \text{lcm}(i, j) \\ =& \sum_{i = 1} ^n \sum_{j = 1} ^n \frac{ij}{\gcd(i, j)} \\ =&\sum_{d = 1} ^ n \sum_{i = 1} ^ {\lfloor \frac n d \rfloor} \sum_{j = 1} ^ {\lfloor \frac n d \rfloor} \frac{id \cdot jd} d [\gcd(i, j) = 1] \\ =&\sum_{d = 1} ^ n d \sum_{i = 1} ^ {\lfloor \frac n d \rfloor} \sum_{j = 1} ^ {\lfloor \frac n d \rfloor} ij [\gcd(i, j) = 1] \\ &\because\sum_{i = 1} ^ n i [\gcd(i, n) = 1] = \frac{\varphi(n)} 2 n \\ \therefore=&\sum_{d = 1} ^ nd\sum_{i= 1} ^ {\lfloor \frac n d \rfloor} i^2\varphi(i) \end{align*} \]考慮快速求 \(S(\lfloor \frac n d \rfloor) = \begin{align*} \sum_{i= 1} ^ {\lfloor \frac n d \rfloor} i^2\varphi(i) \end{align*}\)
顯然,如果 \(f(i) = i^2\varphi(i)\) ,則 \(g = id^2, f * g = \varphi(i)\) 是個不錯的選擇
兩個整除分塊就行了
題意:
已知 \(n\) ,求:
\[\sum_{i = 1} ^ n \sum_{j = 1}^n \sigma(i \cdot j) \]巨難推,我不會,HS切,Orz