欧拉函数

前言

原!式!得!证 !

1. 定义

欧拉函数 \(\varphi(n)\) 表示从 \(1\sim n\) 中与 \(n\) 互质的数的个数。
读作 phi,写作 \(\varphi\)\(\LaTeX:\)$\varphi$,是一个希腊字母。
比如说 \(\varphi(1) = 1\)
当 n 是质数的时候,显然有 \(\varphi(n) = n - 1\)

2.性质与公式

  • 欧拉函数是一个积性函数
    即对于两个正整数 \(a,b\),当 \(\operatorname{gcd}(a,b)=1\) 时,\(\varphi(ab)=\varphi(a)\times \varphi(b)\)
    注意不是任意的两个正整数

  • \(p\) 为质数,则 \(\varphi(p^k)=p^k-p^{k-1}\ \ \ (k\in \mathbb{Z}^+)\)
    证明:
    有引理:若 \(p\) 为质数,则 \(1\sim p^k\) 中有 \(p^{k-1}\)\(p^k\) 的因数,其中 \(k\in \mathbb{Z}^+\)
    我们考虑一个 \(1\sim p^k\) 的数列,可以发现这个数列中每隔 \(p\) 个数就会出现一个 \(p\) 的因数 \(p^1,p^2\cdots p^k\)。而这个数列中有 \(p^{k} \times \frac{1}{p}=p^{k-1}\) 个这样的数列,即有 \(p^{k-1}\) 个因数,故引理得证。
    于是,由欧拉函数的定义,原式得证。

  • \(\varphi(n)=n\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\),其中 \(s\)\(n\) 的质因数种类数,\(p\)\(n\) 的每一种质因数。
    证明:
    由正整数唯一分解定理,\(n=\prod_{i=1}^{s}p_i^{k_i}\),其中 \(p,s\) 的定义如命题,\(k\)\(n\) 的每一种质因数的个数。
    则由于欧拉函数是积性函数,\(\varphi(n)=\prod_{i=1}^{s}\varphi\left(p_i^{k_i}\right)\)
    接着化简:

    \[\begin{aligned} \varphi(n)&=\prod_{i=1}^{s}\varphi\left(p_i^{k_i}\right)\\ &=\prod_{i=1}^{s}\left(p_i^{k_i}-p_i^{k_i-1}\right)\\ &=\prod_{i=1}^{s}p_i^{k_i}\left(1-p_i^{-1}\right)\\ &=n\cdot\prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\\ \end{aligned}\]

    故原式得证。

  • \(n\) 为奇数,则 \(\varphi(n)=\varphi(2n)\)
    证明:
    由上一条公式,\(\varphi(n)=n\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\)
    则由于 \(n\) 是奇数,其质因数分解中一定不包含 \(2\)
    所以,\(2n\) 的质因数分解一定比 \(n\) 多且仅多出了一个 \(2\)
    因此,\(\varphi(2n)\) 可以写作:

    \[\varphi(2n)=2n\cdot \left(1-\frac{1}{2}\right)\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right) \]

    即:

    \[\begin{aligned} \varphi(2n)&=2n\cdot \frac{1}{2}\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\\ &=n\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\\ &=\varphi(n)\\ \end{aligned}\]

    故原式得证。

  • 对于 \(1\sim n\) 的序列,\(n\) 的因数个数为 \(\prod_{i=1}^s\left(k_i+1\right)\),即 \(n-\varphi(n)=\prod_{i=1}^s\left(k_i+1\right)\)
    证明:
    对于一个正整数 \(x\)\(n\) 能够整除 \(x\) 当且仅当 \(x\) 的质因数种类包含于 \(n\)
    则由正整数唯一分解定理,求因数数量就转化成了 \(n\) 质因数数量的排列组合问题。
    即对于一个 \(n\) 的因数 \(x\),其质因数分解一定为 \(p_1^{0\sim k_1}p_2^{0\sim k_2}\cdots p_s^{0\sim k_s}\)
    根据乘法原理,\(n\) 的因数个数为 \(\prod_{i=1}^s\left(k_i+1\right)\)
    原式得证。

  • 对于 \(1\sim n\) 的序列,所有 \(n\) 的因数和为 \(\prod_{i=1}^s\sum_{j=0}^{k_i}(p_i)^{j}\) 乘法分配律简简又单单。
    然后注意到后面一个求和是等比数列直接套等比数列求和公式可以做到 \(O(s)\) 单次询问,预处理出范围内的所有素数就可以到 \(O(ns)\) 的时间复杂度。

  • \(\operatorname{gcd}(a,m)=1\)\(a^{\varphi(n)}\equiv 1 \ \ \ (\operatorname{mod} n)\)
    证明:
    我们把 \(1\sim n\) 中所有与 \(n\) 互质的数列出来,即 \(a_1,a_2\cdots a_{\varphi(n)}\)
    我们把这些数全都乘以 \(a\),即 \(aa_1,aa_2\cdots aa_{\varphi(n)}\)
    由于 \(a\)\(n\) 互质,所以这个数列中的每一个数对 \(n\) 取余后仍与 \(n\) 互质。
    因为这个数列中的数与原数列数量相同,每一个数都不同,每一个数取余 \(n\) 后与 \(n\) 互质,因此这个数列中的数在取余 \(n\) 的条件下与原数列相同,仅是顺序发生了变化
    因为这些数都与 \(n\) 互质,所以它们的乘积也与 \(n\) 互质。
    又因为这个数列中的数在取余 \(n\) 的条件下与原数列相同,仅是顺序发生了变化,所以两数列的积同余于 \(n\)
    即:

    \[\begin{aligned} aa_1\times aa_2\times\cdots \times aa_{\varphi(n)} &\equiv a_1\times a_2\times \cdots a_{\varphi(n)}\ \ \ (\operatorname{mod}n)\\ a^{\varphi(n)}\left(a_1\times a_2\times\cdots \times a_{\varphi(n)}\right)&\equiv a_1\times a_2\times \cdots a_{\varphi(n)}\ \ \ (\operatorname{mod}n)\\ a^{\varphi(n)}&\equiv 1\ \ \ (\operatorname{mod}n) \end{aligned}\]

    故原式得证。
    更特殊的情况:当 \(n\) 为质数,\(\operatorname{gcd}(a,n)=1\) 时,因为当 \(n\) 是质数的时候, \(\varphi(n) = n - 1\),所以:

    \[a^{n-1}\equiv 1\ \ \ (\operatorname{mod}n) \]

    这就是费马小定理

3. 欧拉函数的求解

求解欧拉函数一般不单个求解,而是在执行欧拉筛的时候顺带求出(都性欧拉,都是一家子人)。
在欧拉筛的时候求解欧拉函数也要用到倍数法,我们看看欧拉筛和欧拉函数之间有什么关系:
先贴上欧拉筛的代码,来自我的这篇文章

bool is_prime[1000005];//标记列表
int prime_list[1000005];//质数列表
int num=0;//质数列表的个数

void Euler_Sieve(int n){
	memset(is_prime,1 ,sizeof is_prime);//初始化,所有数都是质数,可以改变标记方式以省去 
	is_prime[1]=0;// 1既不是质数也不是合数 
	for(int i=2;i<=n;i++){
		if(is_prime[i])prime_list[++num]=i;//加入素数列表 
		for(int j=1;j<=num&&i*prime_list[j]<=n;j++){
			is_prime[i*prime_list[j]]=0;//同埃氏筛一样用倍数法标记 
			if(i%prime_list[j]==0){
        	  		/*CASE 1*/	
				break;//退出避免重复标记 
			else{
				/*CASE 2*/
			}
	}
}

(下文把代码中的 prime_list[j] 简写为 \(p_j\)
首先我们知道,在进行欧拉筛时有两种情况,即 \(i\bmod p_j\) 等于 \(0\) 和不等于 \(0\) 这两种情况,此时我们就这两种情况对 \(phi[i\times p_j]\) 的影响进行分类讨论:
\(i\bmod p_j=0\) 时,即 \(p_j\)\(i\) 的一个素因子,也就是说,\(i\times p_j\) 中含有的素因子的种类数不变,根据先前推导出的公式:

\[\varphi(n)=n\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right) \]

也就是 \(\prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\) 这一坨的值不变,那么:

\[\begin{aligned} \varphi(i\times p_j)&=p_j\times i\cdot \prod_{i=1}^{s}\left(1-\frac{1}{p_i}\right)\\ \varphi(i\times p_j)&=p_j\times \varphi(i) \end{aligned}\]

于是可以递推求解。

\(i \bmod p_j \ne 0\) 时,代表 \(i\)\(p_j\) 互质,此时可以通过欧拉函数的积性直接递推:

\[\begin{aligned} \varphi(i\times p_j)&=\varphi(i)\times \varphi(p_j) \end{aligned}\]

将这两种情况体现到代码中即可,注意初始值:

bool is_prime[1000005];//标记列表
int prime_list[1000005];//质数列表
int phi[1000005];//欧拉函数值
int num=0;//质数列表的个数

void Euler_Sieve(int n){
	memset(is_prime,1,sizeof is_prime);//初始化,所有数都是质数,可以改变标记方式以省去
	is_prime[1]=0;//1既不是质数也不是合数
	phi[1]=1//初始值不能忘
	for(int i=2; i<=n; i++){
		if(is_prime[i]){
			prime_list[++num]=i;//加入素数列表
			phi[i]=i-1//质数的欧拉函数值可以直接得到
		}
		for(int j=1; j<=num&&i*prime_list[j]<=n; j++){
			is_prime[i*prime_list[j]]=0;//同埃氏筛一样用倍数法标记
			if(i%prime_list[j]==0){
				/*CASE 1 可以被整除时*/
				phi[i*prime_list[j]]=phi[i]*prime_list[j];
				break;//退出避免重复标记
			}
			else {
				/*CASE 2 两数互质时*/
				phi[i*prime_list[j]]=phi[i]*phi[prime_list[j]];
			}
		}
	}
}

迁移自洛谷

posted @ 2025-02-04 13:05  hm2ns  阅读(39)  评论(0)    收藏  举报