前言:
按 $GrayGoods$ 大佬所说的,所有积性函数都可以线筛
所以在这里我只给出质数,欧拉函数和莫比乌斯函数的筛法(逃~~~)
正文:
质数
筛质数好像有很多种方法,这里只介绍两种
第一种是埃筛暴力筛
这种筛法的优点是只需开一个 $bool$ 数组
但复杂度是 $O(nloglogn)$ 的
代码还是比较好理解的
bool is_prime[maxn]; void check_prime(int n) { for(int i=2;i<=n;i++) is_prime[i]=1; for(int i=0;i<=n;i++) { if(is_prime[i]==1) { for(int j=2;j*i<=n;j++) is_prime[i*j]=0; } } }
另一种是欧拉筛,也就我们所说的线筛
这种筛法的优点是严格 $O(n)$ 的时间复杂度
但是要另开一个数组记录所有的质数
int cnt,prime[maxn]; bool not_prime[maxn]; void check_prime(int n) { not_prime[1]=1; for(int i=2;i<=n;i++) { if(!not_prime[i]) prime[++cnt]=i; for(int j=1;j<=cnt&&i*prime[j]<=n;j++) { not_prime[i*prime[j]]=1; if(i%prime[j]==0) break;//保证每个数只被它最小的质因子筛去 } } }
欧拉函数
欧拉函数的定义 $φ(n)$ 表示的是比 $n$ 小的与 $n$ 互质的正整数的个数,特别的 $φ(1)=1$
有一个很显然的性质是如果 $n$ 是一个质数,那么 $φ(n)=n-1$
同时作为一个积性函数,$φ(n imes m)=φ(n) imes φ(m)$ ,当且仅当 $gcd(n,m)=1$
所以当 $i mod prime[j] eq 0$ 即 $gcd(i,prime[j])=1$ 时
$φ(i imes prime[j])=φ(i) imes φ(prime[j])$
而当 $i mod prime[j]=0$ 时
我们可以知道 $i$ 中包含了 $n=i*prime[j]$ 的所有因子
根据欧拉函数的另一个性质($cnt$ 为因子个数)
我们有 $φ(n)=n imes prod_{k=1}^{cnt} dfrac{p_k-1}{p_k}$
所以 $φ(n)=prime[j] imes i imes prod_{k=1}^{cnt} dfrac{p_k-1}{p_k}$
所以 $φ(n)=prime[j] imes φ(i)$
这样我们就可以得到
$φ(i*prime[j])=φ(i)*prime[j]$
然后稍微魔改一下欧拉筛,就可以线性筛出欧拉函数
int phi[maxn]; int cnt,prime[maxn]; bool not_prime[maxn]; void check_phi(int n) { phi[1]=1; not_prime[1]=1; for(int i=2;i<=n;i++) { if(!not_prime[i]) { phi[i]=i-1; prime[++cnt]=i; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++) { not_prime[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } }
莫比乌斯函数
关于莫比乌斯函数 $μ(n)$ 的定义
$(1)$ $μ(1)=1$
$(2)$ 当 $n$ 存在平方因子时 $μ(n)=0$
$(3)$ 当 $n$ 是质数或奇数个不同质数之积时 $μ(n)=-1$
$(4)$ 当 $n$ 是偶数个不同质数之积时 $μ(n)=1$
写成表达式的形式就是
$μ(n)=egin{cases} quad 1 quad quad quad ;;; n=1 \ (-1)^k quad n=p_1p_2cdots p_k\ quad 0 quad quad quad; ; others end{cases}$
同样的,它也是一个积性函数
$μ(n imes m)=μ(n) imes μ(m)$ ,当且仅当 $gcd(n,m)=1$
所以当 $i mod prime[j] eq 0$ 即 $gcd(i,prime[j])=1$ 时
$μ(i imes prime[j])=μ(i) imes μ(prime[j])$
而 $μ(prime[j])=-1$ ,所以我们可以直接写成
$μ(i imes prime[j])=-μ(i)$
这样又可以愉快地魔改欧拉筛了
int miu[maxn]; int cnt,prime[maxn]; bool not_prime[maxn]; void check_miu(int n) { miu[1]=1; not_prime[1]=1; for(int i=2;i<=n;i++) { if(!not_prime[i]) { miu[i]=-1; prime[++cnt]=i; } for(int j=1;j<=cnt&&i*prime[j]<=n;j++) { not_prime[i*prime[j]]=1; if(i%prime[j]==0) { miu[i*prime[j]]=0; break; } else miu[i*prime[j]]=-miu[i]; } } }
后序:
个人感觉筛 $φ$ 和筛 $μ$ 的方式差不多
都是在欧拉筛的基础上,根据积性函数的性质魔改了一下
$ps:$ 现在你会线筛 $μ$ 了,你可以做莫反的题了(逃~~~)