线性筛筛质数及积性函数
一般而言,线性筛可以筛几乎所有积性函数,同时其思路清晰代码简短。
不过一般而言筛积性函数都是用于整除分块后用积性函数的前缀和。这时线性筛就有可能超时了。不过在很多情况下线性筛还是可堪一用的。
莫比乌斯函数
code
mu[1]=1;int cnt=0,up=min(n,m);sign[0]=sign[1]=1;ni=ksm(2,p-2);
for(int i=2;i<=up;i++){
if(!sign[i]) zhi[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*zhi[j]<=up;j++){
sign[i*zhi[j]]=1;
if(i%zhi[j]==0) {mu[i*zhi[j]]=0;break;}
mu[i*zhi[j]]=-mu[i];
}
}
这段代码同时用线性筛筛出了质数和莫比乌斯函数。筛出质数的原理不用多讲。
而 \(\mu\) 的原理略显复杂:
这个数本身是质数时显然根据定义 \(\mu\) 的值是-1
用当前数去筛的时候,如果 \(i\bmod zhi_j=0\) 就表示 \(i\) 有 \(zhi_j\) 这个质因子,就表示 \(i\times zhi_j\) 至少有两个 \(zhi_j\) 这个质因子。\(\mu\) 就是0.
如果不是上面的情况,那就比 \(i\) 多出了1个 \(zhi_j\) 这个质因子。无论当前的 \(\mu\) 是0还是-1还是1,直接取负都是正确的。
欧拉函数
code
int cnt=0;sign[1]=sign[0]=1;phi[1]=1;
for(int i=2;i<=10000000;i++)
{
if(!sign[i]) zhi[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*zhi[j]<=10000000;j++)
{
sign[i*zhi[j]]=1;
if(i%zhi[j]==0){phi[i*zhi[j]]=phi[i]*zhi[j];break;}
phi[i*zhi[j]]=phi[zhi[j]]*phi[i];
}
}
这里筛出了质数和欧拉函数。
欧拉函数的原理相对简单:
是质数时由定义直接得值为 \(p-1\)。
筛的时候,如果 \(i\) 与 \(zhi_j\) 不互质,则由定义(?)式有
\[\begin{aligned}
\varphi(n)&=n\prod_{p_i|n}\frac{p_i-1}{p_i} \\
&=zhi_j\times\frac{n}{zhi_j}\prod_{p_i|n\wedge p_i\ne zhi_j}\frac{p_i-1}{p_i}\\
&=zhi_j\times \varphi(\frac{n}{zhi_j})
\end{aligned}
\]
这个比较直观。
如果不互质,那由于欧拉函数是积性函数,直接乘起来就好了。

浙公网安备 33010602011771号