目录
- 欧拉函数
- 欧拉函数的定义
- 欧拉函数的公式
- 欧拉函数的公式推导
- 欧拉定理
- 典型例题
- 代码实现
- 筛法求欧拉函数
- 思路分析
- 经典例题
- 代码实现
欧拉函数
欧拉函数的定义
对于任意正整数 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;
}