线性筛筛质数及积性函数

一般而言,线性筛可以筛几乎所有积性函数,同时其思路清晰代码简短。
不过一般而言筛积性函数都是用于整除分块后用积性函数的前缀和。这时线性筛就有可能超时了。不过在很多情况下线性筛还是可堪一用的。

莫比乌斯函数

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} \]

这个比较直观。
如果不互质,那由于欧拉函数是积性函数,直接乘起来就好了。

posted @ 2025-02-08 15:22  all_for_god  阅读(18)  评论(0)    收藏  举报