杜教筛学习笔记
计算 \(S(n)=\sum_{i=1}^n f(i)\)
对于一个积性函数 \(g\),有(第二行是将 \(i,j\) 分别枚举 \(d,\frac{n}{d}\):
然后把这个求和式的第一项拿出来,就有了:
这个就是杜教筛的主要套路了(
一般对这个 \(S\left(\lfloor\frac{n}{i}\rfloor\right)\) 整除分块来递归地求解
至于复杂度,线性筛预处理前 \(n^{\frac{2}{3}}\) 然后剩下的再递归求的复杂度是 \(O(n^{\frac{2}{3}})\)
多测的时候还可以开个 map 把已经求过的值存下来
一个模板题:https://www.luogu.com.cn/problem/P4213
求 \(\varphi\)
此时肯定要令 \(f=\varphi\),然后问题是如何找到一个合适的 \(g\)
由于想到 \(\varphi * \operatorname{1}=\operatorname{Id}\),所以可以令 \(g=\operatorname{1}\)
此时可以发现,\(g(i)\) 和 \(\sum_{i=1}^n (f*g)(i)\) 都很好求,于是可以直接杜教筛
inline long long get_phi(int n){
if(n<=maxn) return phi[n];
if(ans_phi.find(n)!=ans_phi.end()) return ans_phi[n];
long long ans=((long long)n*(n+1ll))>>1;
for(reg unsigned int l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=(r-l+1)*get_phi(n/l);
}
return ans_phi[n]=ans;
}
求 \(\mu\)
令 \(f=\mu,g=\operatorname{1}\),于是就有 \(f*g=\epsilon\)
那就做完了
inline int get_mu(int n){
if(n<=maxn) return mu[n];
if(ans_mu.find(n)!=ans_mu.end()) return ans_mu[n];
long long ans=1;
for(reg unsigned int l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=(r-l+1)*get_mu(n/l);
}
return ans_mu[n]=ans;
}
总而言之就是想办法找 \(g\)
像 P3768 简单的数学题 推完式子有一部分是 \(\varphi(k)k^2\) 的前缀和,于是就可以构造 \(f=\operatorname{Id}^2\cdot \varphi,g=\operatorname{Id}^2\),然后就能发现 \(\sum_{i=1}^n (f*g)(i)=n^3\) 了
\(\epsilon=\mu * 1\)
\(d=1 * 1\)
\(\sigma=\operatorname{id} * 1\)
\(\varphi=\mu * \operatorname{id}\)
\(\operatorname{id}=\varphi * 1\)