目录
- 欧拉函数
- 欧拉函数的定义
- 欧拉函数的公式
- 欧拉函数的公式推导
- 欧拉定理
- 典型例题
- 代码实现
- 筛法求欧拉函数
- 思路分析
- 经典例题
- 代码实现
欧拉函数
欧拉函数的定义
对于任意正整数 n n n,欧拉函数 φ ( n ) φ(n) φ(n) 表示小于或等于 n n n 的正整数中,与 n n n 互质的正整数个数。
例如:
- φ ( 1 ) = 1 φ(1) = 1 φ(1)=1,因为 1 1 1 只与 1 1 1 互质。
- φ ( 6 ) = 2 φ(6) = 2 φ(6)=2,因为与6互质的数有 1 1 1 和 $5,共 2 2 2 个。
- φ ( 10 ) = 4 φ(10) = 4 φ(10)=4,因为与10互质的数有 1 、 3 、 7 1、3、7 1、3、7 和 9 9 9,共 4 4 4 个。
欧拉函数的公式
对于任意正整数 n n n, φ ( n ) = n ∗ ( 1 − 1 P 1 ) ∗ ( 1 − 1 P 2 ) ∗ . . . ∗ ( 1 − 1 P k ) φ(n) = n * (1 - \frac{1}{P_1}) * (1 - \frac{1}{P_2}) * ... * (1 - \frac{1}{P_k}) φ(n)=n∗(1−P11)∗(1−P21)∗...∗(1−Pk1),其中, P 1 , P 2 , . . . , P k P_1, P_2, ..., P_k P1,P2,...,Pk 是 n n n 的不同的质因数。
欧拉函数公式,只与因子相关,与指数无关。
例如:
φ ( 10 ) = 10 ∗ ( 1 − 1 2 ) ∗ ( 1 − 1 5 ) = 4 φ(10) = 10 * (1 - \frac{1}{2}) * (1 - \frac{1}{5}) = 4 φ(10)=10∗(1−21)∗(1−51)=4
φ ( 15 ) = 15 ∗ ( 1 − 1 3 ) ∗ ( 1 − 1 5 ) = 8 φ(15) = 15 * (1 - \frac{1}{3}) * (1 - \frac{1}{5}) = 8 φ(15)=15∗(1−31)∗(1−51)=8
欧拉函数的公式推导
利用容斥原理的推导过程:
对数字N进行质因数分解,可得
N = P 1 r 1 ∗ P 2 r 2 ∗ P 3 r 3 ∗ . . . ∗ P k r k N=P_1^{r_1}*P_2^{r_2}*P_3^{r_3}*...*P_k^{r_k} N=P1r1∗P2r2∗P3r3∗...∗Pkrk
由于不能与 N N N 不互质,所以 1 1 1 ~ N N N 不可包含 P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 这些质因子。
把 P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 的倍数都减去,分别减去 N P 1 , N P 2 , . . . , N P k \frac{N}{P_1},\frac{N}{P_2},...,\frac{N}{P_k} P1N,P2N,...,PkN 个。
如图所示:
但是由于 P 1 , P 2 , . . . , P k P_1,P_2,...,P_k P1,P2,...,Pk 不同质因子的倍数可能会出现重复,有些数重叠的数会被多次减去。如图中重叠部分会被多次相减,因此要补上重叠的数。比如某个数,是 P 2 P_2 P2 的倍数,也是 P 3 P_3 P3 的倍数,就减了两回,还需要再加回来 P 2 ∗ P 3 P_2∗P_3 P2∗P3 的倍数,换做是其他的组合就是 N P 1 ∗ P 2 , N P 1 ∗ P P 3 , . . . , N P 1 ∗ P k , . . \frac{N}{P_1*P_2},\frac{N}{P_1*P_P3},...,\frac{N}{P_1*P_k},.. P1∗P2N,P1∗PP3N,...,P1∗PkN,..
但是更多质因子重叠的部分又会弥补至减去之前的状态,得继续减去。如 P 1 ∗ P 2 ∗ P 3 P_1*P_2*P_3 P1∗P2∗P3这样的更多质因子重叠的部分,而后就像之前一样一减一加最终推出结果。
φ ( N ) = N ∗ ( 1 − 1 P 1 ) ∗ ( 1 − 1 P 2 ) ∗ . . . ∗ ( 1 − 1 P k ) φ(N) = N * (1 - \frac{1}{P_1}) * (1 - \frac{1}{P_2}) * ... * (1 - \frac{1}{P_k}) φ(N)=N∗(1−P11)∗(1−P21)∗...∗(1−Pk1)
欧拉定理
如果 a a a 和 n n n 是正整数,且 a a a 与 n n n 互质,则 a φ ( n ) ≡ 1 ( m o d n ) a^{φ(n)} ≡ 1 (\mod n) aφ(n)≡1(modn)
如果 n n n 为质数,则 a n − 1 ≡ 1 ( m o d n ) a^{n-1} ≡ 1 (\mod n) an−1≡1(modn)
典型例题
题目描述:
给定 n 个正整数 ai,请你求出每个数的欧拉函数。
输入格式:
第一行包含整数 n。
接下来 n 行,每行包含一个正整数 ai。
输出格式:
输出共 n 行,每行输出一个正整数 ai 的欧拉函数。
数据范围:
1 ≤ n ≤ 100 , 1 ≤ a i ≤ 2 × 1 0 9 1≤n≤100,1≤a_i≤2×10^9 1≤n≤100,1≤ai≤2×109
输入样例:
3
3
6
8
输出样例:
2
2
4
代码实现
res
对不同的质数只需计算一次,不要将res的计算放到循环中。
res
计算过程中要避免出现小数的情况,将除法提前与大数进行。
#define _CRT_NO_SECURE_WARNINGS
#include<iostream>using namespace std;int phi(int x)
{int res = x;for (int i = 2; i <= x / i; ++i){if (x % i) continue;// res对不同的质数只需计算一次,不要将res的计算放到循环中res = res / i * (i - 1); // 注意避免出现小数情况while (x % i == 0) x /= i;}if (x > 1) res = res / x * (x - 1);return res;
}
int main()
{int n;cin >> n;while (n--){int a;cin >> a;cout << phi(a) << endl;}return 0;
}
筛法求欧拉函数
思路分析
- 如果这个数是质数,那么对质数 i i i 的欧拉函数值是 p h i [ i ] = i − 1 phi[i]=i−1 phi[i]=i−1。
- 如果 i i i % p r i m e s [ j ] = = 0 primes[j] == 0 primes[j]==0,那么 p h i [ i ∗ p r i m e s [ j ] ] = p h i [ i ] × p r i m e s [ j ] phi[i*primes[j]]=phi[i]×primes[j] phi[i∗primes[j]]=phi[i]×primes[j]。(相当于 i i i 中的质因子包括了 p r i m e s [ j ] primes[j] primes[j])
- 如果 i i i % p r i m e s [ j ] primes[j] primes[j] ! = 0 != 0 !=0,那么 p h i [ i ∗ p r i m e s [ j ] ] = p h i [ i ] × ( p r i m e s [ j ] − 1 ) phi[i*primes[j]]=phi[i]×(primes[j] - 1) phi[i∗primes[j]]=phi[i]×(primes[j]−1)。(通过公式变形得来)
经典例题
题目描述:
给定一个正整数 n n n,求 1 1 1 ~ n n n 中每个数的欧拉函数之和。
输入格式:
共一行,包含一个整数 n n n。
输出格式:
共一行,包含一个整数,表示 1 1 1 ~ n n n 中每个数的欧拉函数之和。
数据范围:
1 < n < 1 0 6 1<n<10^6 1<n<106
输入样例:
6
输出样例:
12
代码实现
#define _CRT_NO_SECURE_WARNINGS
#include<iostream>using namespace std;const int N = 1e6 + 10;
int phi[N], primes[N], cnt;
bool st[N];
void get_eulers(int n)
{for (int i = 2; i <= n; ++i){phi[1] = 1;if (!st[i]){phi[i] = i - 1;primes[cnt++] = i;}for (int j = 0; primes[j] <= n / i; ++j){st[primes[j] * i] = true;if (i % primes[j] == 0){phi[primes[j] * i] = phi[i] * primes[j];break;}phi[primes[j] * i] = phi[i] * (primes[j] - 1);}}
}
int main()
{int n, res = 0;cin >> n;get_eulers(n);for (int i = 1; i <= n; ++i) res += phi[i];cout << res << endl;return 0;
}