[学习笔记]线性筛
素数
欧拉筛法保证每个合数只会被其最小的素数筛掉,所以复杂度是线性的。
int p[N],n,cnt;
bool b[N];
inline void prime(){
b[0]=b[1]=true;
for(int i=2;i<=n;++i){
if(!b[i]) p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=n;++j){
b[i*p[j]]=true;
if(!(i%p[j])) break;
}
}
}
每次\(p[j]|i\)时跳出循环能保证每个合数只会被其最小的素数筛掉,因为\(i\;\times\;p[k](k>j)\)的最小素数为\(p[j]\)。
我们还能用此方法,筛出其他一些积性函数的值。
积性函数
若\((a,b)=1\),则\(f(ab)=f(a)\;\times\;f(b)\).
欧拉函数
欧拉函数\(\phi(x)\)的定义:小于等于\(x\)的正整数中与\(x\)互质的数的个数。
\(\phi(x)=\begin{cases}1&x=1\\x-1&x\;is\;prime\\x\prod_{i=1}^{k}(\frac{p_{i}-1}{p_{i}})&x=p_1^{a_1}\times{p_2^{a_2}}\times\dots\times{p_k^{a_k}}\\\end{cases}\)
证明:
如果\(n\)为某一素数\(p\),则\(\phi(p)=p-1\).
如果\(n\)为某一素数\(p\)的幂次\(p^a,\phi(p^a)=(p-1)\;\times\;p^{a-1}\).
欧拉函数是积性函数,即当\((a,b)=1\)时\(f(ab)=f(a)\;\times\;f(b)\).
若\(x=p_1^{a_1}\;\times\;p_2^{a_2}\;\times\dots\times\;p_k^{a_k}\),则\(\phi(x)=\prod_{i=1}^{k}(p_i-1)\;\times\;p_i^{a_i-1}=x\prod_{i=1}^{k}\frac{p_i-1}{p_i}\).
设\(p\)为\(x\)最小的质数,\(x'=x/p\),在线性筛中,\(x\)被筛\(p\;\times\;x'\)掉。
当\(x'\;mod\;p\not=0\)时,\(\phi(x)=p\;\times\;x'\times\;(\frac{p-1}{p})\prod_{i=1}^{k'}(\frac{p_i-1}{p_i})=(p-1)\;\;\times\;\phi(x')\);
当\(x'\;mod\;p=0\)时,\(\phi(x)=p\;\times\;x'\;\times\;\prod_{i=1}^{k'}(\frac{p_i-1}{p_i})=p\;\times\;\phi(x')\).
int p[N],phi[N],n,cnt;
bool b[N];
inline void prime(){
b[0]=b[1]=true;phi[1]=1;
for(int i=2;i<=n;++i){
if(!b[i]){
p[++cnt]=i;phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*p[j]<=n;++j){
b[i*p[j]]=true;
if(!(i%p[j])){
phi[i*p[j]]=p[j]*phi[i];break;
}
phi[i*p[j]]=(p[j]-1)*phi[i];
}
}
}
莫比乌斯函数
莫比乌斯函数\(\mu(x)\)的定义:
\(\mu(x)=\begin{cases}1&x=1\\(-1)^{k}&x=p_{1}^{a_{1}}p_{2}^{a_{2}}\;\dots\;p_{k}^{a_{k}}(a_{i}=1)\\0&x=p_{1}^{a_{1}}p_{2}^{a_{2}}\;\dots\;p_{k}^{a_{k}}(max\{a_{i}\}>1)\end{cases}\)
显然当\(x\)是质数时,\(\mu(x)=-1\);
当\(x\)不是质数时,设\(p\)为\(x\)最小的质数,\(x'=x/p\),在线性筛中,\(x\)被筛\(p\;\times\;x'\)掉。
当\(x'\;mod\;p\not=0\)时,当\(\mu(x')\not=0\)时,显然\(a_{i}=1,\mu(x)=-\mu(x')\);
\(\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\)当\(\mu(x')=0\)时,\(\mu(x)=0\),即\(\mu(x)=-\mu(x')\);
当\(x'\;mod\;p=0\)时,显然\(max\{a_{i}\}>1\),\(\mu(x)=0\)。
int p[N],mu[N],n,cnt;
bool b[N];
inline void prime(){
b[0]=b[1]=true;mu[1]=1;
for(int i=2;i<=n;++i){
if(!b[i]){
p[++cnt]=i;mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<=n;++j){
b[i*p[j]]=true;
if(!(i%p[j])){
mu[i*p[j]]=0;break;
}
mu[i*p[j]]=-mu[i];
}
}
}