欧拉函数小结

定义

\(\varphi(x)\) 指对于 \(\forall i\in [1,x]\) ,满足 \(\gcd(i,x)=1\)\(i\) 的个数。

也就是小于等于 \(x\) 的正整数中与其互质的数的个数。


基本推论

\(\varphi(x)=x-1\quad(x\in \mathbb{P})\)


$ \begin{aligned} \varphi(p^k)& =pk-p \quad(p\in \mathbb{P},k\in \Z^) \ &= p^k(1-\frac{1}{p})\quad(p\in \mathbb{P},k\in \Z^)\end{aligned}$

这是因为只有当一个数不包含质数 \(p\) ,才可能与 \(x\) 互质。而包含质数 \(p\) 的数一共有$ p^{k-1} $个,即 \(1×p、2×p、3×p、...、p^{k-1}×p\) ,把它们去除,剩下的就是与n互质的数。


\(x=p_1 \times p_2 \quad (\gcd(p_1,p_2)=1)\)

\(\varphi(x)=\varphi(p_1p_2) = \varphi(p_1)\varphi(p_2)\)

证明较为复杂。


由上式推广

\(n=p_1^{k_1}p_2^{k_2}…p_x^{k_x}\quad(p_1,p_2… p_n\in \mathbb{P})\)

$ \begin{aligned} \varphi(n)&=\varphi(p_1{k_1})\varphi(p_2)…\varphi(p_x^{k_x})\ &= p_1{k_1}p_2…p_x^{k_x}(1-\frac{1}{p_1})(1-\frac{1}{p_2})…(1-\frac{1}{p_x}) \ &= n(1-\frac{1}{p_1})(1-\frac{1}{p_2})…(1-\frac{1}{p_x}) \end{aligned}$

于是我们就得到了欧拉函数的通项

\[\varphi(n)=n\prod\limits_{d\in \mathbb{P}\&d|n}^n(1-\frac{1}{d}) \]


由通项我们可以推导,若 \(y|x\) ,则

\(\varphi(x\times y)=\varphi(x) \times y\)


由通项我们还可以推出

\(\varphi(n!)=\begin{cases} \varphi((n-1)!)\times(n-1)&n\in \mathbb{P} \\\varphi((n-1)!)\times n & n\notin\mathbb{P} \end{cases}\)

可以在 \(O(n)\) 时间内求解 \(\varphi(n!)\)


计算

  • 单个求法

在上文中我们推导出了欧拉函数通项,

配合质数筛可以在 \(O(因子个数)\) 内求出 $\varphi(n) $。

int phi(int x){
	int ans=x;
	for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;++i){
		if(x%prime[i]) continue;
		ans=ans/prime[i]*(prime[i]-1);
		while(x%prime[i]==0) x/=prime[i];
	}
	if(x>1) ans=ans/x*(x-1);
	return ans;
}
  • 多个求法

然而我们在某些时候需要求出连续区间内的所有 \(\varphi(i)\) 值,这时候上述求法的复杂度就有些劣

涉及 \(10^6\) 及以上的数据时容易被卡常,因此我们需要更快的方式。

涉及到线性,质数,我们可以自然联想到欧拉筛。

回忆一下欧拉筛的实现步骤:

  1. 遍历每个 \(x\) ,观察是否为质数。
  2. 使用先前筛出的质数和遍历到的 \(x\) ,筛掉接下来的合数。

我们知道,欧拉筛的过程是线性的,也就是每个数最多遍历一遍,利用这个性质,我们可以做到线性求解。

第一步中,对于 \(x\in \mathbb{P}\)\(\varphi(x)=x-1\)

第二步中,对于合数,我们发现:

对于任意 \(y=x*p\quad(p\in \mathbb{P} \&x> p)\), 总有

\(\varphi(y)=\varphi(x)\times \varphi(p)\quad(p\nmid x)\)

\(\varphi(y)=\varphi(x)\times p\quad(p\mid x)\)

然后我们就可以代码实现。

void init(){
	isp[0]=isp[1]=1;phi[1]=1;
	for(int i=2;i<N;++i){
		if(!isp[i]) pri[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&pri[j]*i<=N;++j){
			isp[pri[j]*i]=1;
			if(i%pri[j]) phi[pri[j]*i]=phi[i]*phi[pri[j]];
			else phi[pri[j]*i]=pri[j]*phi[i];
			if(i%pri[j]==0) break;
		}
	}
	//for(int i=1;i<N;++i) sum[i]=sum[i-1]+phi[i];
}

参考资料

https://blog.csdn.net/wrwhahah/article/details/82704053

https://www.cnblogs.com/bibibi/p/10257292.html

posted @ 2024-12-17 22:48  lxg_swrz  阅读(52)  评论(0)    收藏  举报