文章目录
- 欧拉函数
-
- 互质(Coprime)
- [欧拉函数(Euler's Totient Function)](#欧拉函数(Euler's Totient Function))
- 欧拉函数的计算公式
- [试除法(定义法)求欧拉函数:1个数- O ( log n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )](#试除法(定义法)求欧拉函数:1个数- O ( log n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n ))
- [线性筛法求欧拉函数:n个数- O ( n ) O(n) O(n)](#线性筛法求欧拉函数:n个数- O ( n ) O(n) O(n))
欧拉函数
互质(Coprime)
若两个整数 a , b a, b a,b 满足它们的最大公约数为 1 ,即
gcd ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1
则称 a a a 与 b b b 互质 (或称互素)。
等价表述: a a a 与 b b b 没有任何大于 1 的公共因子。
欧拉函数(Euler's Totient Function)
欧拉函数 φ ( n ) \varphi(n) φ(n) 定义为:
在 1 1 1 到 n n n 中 ,与 n n n 互质的正整数的个数。
即
φ ( n ) = ∣ { , k ∈ Z + ∣ 1 ≤ k ≤ n , gcd ( k , n ) = 1 , } ∣ \varphi(n) = \left| \{, k \in \mathbb{Z}^+ \mid 1 \le k \le n,\ \gcd(k,n)=1 ,\} \right| φ(n)= {,k∈Z+∣1≤k≤n, gcd(k,n)=1,}
欧拉函数的计算公式
设正整数 n n n 的质因数分解为
n = p 1 k 1 p 2 k 2 ⋯ p m k m n = p_1^{k_1} p_2^{k_2} \cdots p_m^{k_m} n=p1k1p2k2⋯pmkm
其中 p i p_i pi 为互不相同的质数 ,则
φ ( n ) = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p m ) \varphi(n) = n \left(1 - \frac{1}{p_1}\right)\left(1 - \frac{1}{p_2}\right)\cdots\left(1 - \frac{1}{p_m}\right) φ(n)=n(1−p11)(1−p21)⋯(1−pm1)
证明思路
- 先删去能被p1倍数的
- 删去p1和p2倍数的
- 删去p1、p2和p3倍数的
- 因此类推,使用容斥原理避免重复删除
证明过程
可以用"从 1 1 1 到 n n n 中,删去所有与 n n n 不互质的数"这个思路,用容斥原理做一个很自然的证明。
设
n = p 1 k 1 p 2 k 2 ⋯ p m k m n=p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m} n=p1k1p2k2⋯pmkm
其中 p 1 , p 2 , ... , p m p_1,p_2,\dots,p_m p1,p2,...,pm 是 n n n 的全部不同质因子。
欧拉函数 φ ( n ) \varphi(n) φ(n) 表示在 1 , 2 , ... , n 1,2,\dots,n 1,2,...,n 中,与 n n n 互质的正整数个数。
因此,我们只要统计:在 1 1 1 到 n n n 中,有多少个数 不被任何一个 p i p_i pi 整除。
首先看全集
1 , 2 , ... , n {1,2,\dots,n} 1,2,...,n
一共有 n n n 个数。
对于每个质因子 p i p_i pi,设
A i = 1 ≤ k ≤ n : p i ∣ k A_i={1\leq k\leq n:\ p_i\mid k} Ai=1≤k≤n: pi∣k
即 A i A_i Ai 表示"能被 p i p_i pi 整除的数"的集合。
那么,与 n n n 不互质的数,恰好就是落在并集
A 1 ∪ A 2 ∪ ⋯ ∪ A m A_1\cup A_2\cup\cdots\cup A_m A1∪A2∪⋯∪Am
中的那些数。
所以
φ ( n ) = n − ∣ A 1 ∪ A 2 ∪ ⋯ ∪ A m ∣ \varphi(n)=n-\left|A_1\cup A_2\cup\cdots\cup A_m\right| φ(n)=n−∣A1∪A2∪⋯∪Am∣
接下来用容斥原理计算这个并集的大小。
因为 p i ∣ n p_i\mid n pi∣n,所以在 1 1 1 到 n n n 中,能被 p i p_i pi 整除的数有
∣ A i ∣ = n p i |A_i|=\frac{n}{p_i} ∣Ai∣=pin
同理,同时被 p i , p j p_i,p_j pi,pj 整除的数,就是被 p i p j p_ip_j pipj 整除的数,因此有
∣ A i ∩ A j ∣ = n p i p j |A_i\cap A_j|=\frac{n}{p_ip_j} ∣Ai∩Aj∣=pipjn
类似地,
∣ A i 1 ∩ A i 2 ∩ ⋯ ∩ A i r ∣ = n p i 1 p i 2 ⋯ p i r |A_{i_1}\cap A_{i_2}\cap\cdots\cap A_{i_r}| =\frac{n}{p_{i_1}p_{i_2}\cdots p_{i_r}} ∣Ai1∩Ai2∩⋯∩Air∣=pi1pi2⋯pirn
于是由容斥原理,
∣ A 1 ∪ ⋯ ∪ A m ∣ = ∑ i n p i − ∑ i < j n p i p j + ∑ i < j < k n p i p j p k − ⋯ + ( − 1 ) m + 1 n p 1 p 2 ⋯ p m |A_1\cup\cdots\cup A_m|=\sum_{i}\frac{n}{p_i} -\sum_{i<j}\frac{n}{p_ip_j} +\sum_{i<j<k}\frac{n}{p_ip_jp_k} -\cdots +(-1)^{m+1}\frac{n}{p_1p_2\cdots p_m} ∣A1∪⋯∪Am∣=i∑pin−i<j∑pipjn+i<j<k∑pipjpkn−⋯+(−1)m+1p1p2⋯pmn
因此
φ ( n ) = n − ∣ A 1 ∪ ⋯ ∪ A m ∣ \varphi(n)=n-\left|A_1\cup\cdots\cup A_m\right| φ(n)=n−∣A1∪⋯∪Am∣
就变成
φ ( n ) = n ( 1 − ∑ i 1 p i + ∑ i < j 1 p i p j − ∑ i < j < k 1 p i p j p k + ⋯ + ( − 1 ) m 1 p 1 p 2 ⋯ p m ) \varphi(n)= n\left( 1-\sum_i\frac{1}{p_i} +\sum_{i<j}\frac{1}{p_ip_j} -\sum_{i<j<k}\frac{1}{p_ip_jp_k} +\cdots +(-1)^m\frac{1}{p_1p_2\cdots p_m} \right) φ(n)=n 1−i∑pi1+i<j∑pipj1−i<j<k∑pipjpk1+⋯+(−1)mp1p2⋯pm1
最后注意到,括号里的式子正好就是下面乘积展开后的结果:
( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p m ) \left(1-\frac{1}{p_1}\right)\left(1-\frac{1}{p_2}\right)\cdots\left(1-\frac{1}{p_m}\right) (1−p11)(1−p21)⋯(1−pm1)
所以得到
φ ( n ) = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p m ) \varphi(n)=n\left(1-\frac{1}{p_1}\right)\left(1-\frac{1}{p_2}\right)\cdots\left(1-\frac{1}{p_m}\right) φ(n)=n(1−p11)(1−p21)⋯(1−pm1)
这就是所要证明的公式。
试除法(定义法)求欧拉函数:1个数- O ( log n ) − O ( n ) O(\log n)-O(\sqrt{n}) O(logn)−O(n )
实现
- 素因子分解+定义
- 防止溢出的技巧,先除后乘:(1-1/p)=(p-1)/p=/p*(p-1)
cpp
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
int a;
cin >> a;
int res = a;
for (int j = 2; j <= a / j; j++) {
if (a % j == 0) {
while (a % j == 0) {
a /= j;
}
res = res / j *(j-1);
}
}
if (a > 1) {
res = res / a * (a - 1);
}
cout << res << endl;
}
}
线性筛法求欧拉函数:n个数- O ( n ) O(n) O(n)
实现
- 引入
phi数组,phi[i]表示i的欧拉函数值 - 注意:素数p的欧拉函数值为p-1,一定要记得赋值!一定要记得赋值!一定要记得赋值!
- 如果
i % prime == 0:则i已经i包含prime这个素因子 (素因子的次数不影响欧拉函数的值),所以根据欧拉的计算公式,只需要补齐prime即可(N=prime*i) - 如果
i % prime != 0,则i不包含prime这个素因子,因此需要补齐prime和(1-1/prime),化简得到就是prime-1.
cpp
void solve() {
cin >> n;
for (int i = 2; i <= n; i++) {
if (isprimes[i]) {
phi[i] = i - 1;
primes.push_back(i);
}
for (auto prime : primes) {
if (prime > n / i)continue;// subscript out of range
isprimes[prime * i] = 0;
if (i % prime == 0) {
phi[i * prime] = phi[i] * prime;
break;
}
else {
phi[i * prime] = phi[i] * (prime - 1);
}
}
}
ll res = 0;
for (int i = 1; i <= n; i++) {
res += (ll)phi[i];
}
cout << res;
}