欧拉函数的定义
欧拉函数
φ
(
N
)
\varphi(N)
φ(N),指
1
−
N
1-N
1−N 中与
N
N
N 互质的数的个数。
当
N
=
1
N=1
N=1 时,
φ
(
N
)
=
1
\varphi(N)=1
φ(N)=1 。当
N
N
N 为质数,
φ
(
N
)
=
N
−
1
\varphi(N)=N-1
φ(N)=N−1。
特殊性质
欧拉函数是积性函数,也就是对于两个互质数 x x x 和 y y y, φ ( x × y ) = φ ( x ) × φ ( y ) \varphi(x\times y)=\varphi(x)\times \varphi(y) φ(x×y)=φ(x)×φ(y)
当 N N N 是一个大于 2 2 2 的整数并且 φ ( N ) \varphi(N) φ(N) 是偶数,那么与 N N N 互质的数的和是 N × φ ( N ) 2 \frac{N\times\varphi(N)}{2} 2N×φ(N)
∑ p ∣ N φ ( p ) = N \sum_{p|N}\varphi(p)=N ∑p∣Nφ(p)=N
如果 x x x 和 y y y 互质,那么 y ∣ ( x φ ( y ) − 1 ) y|(x^{\varphi(y)}-1) y∣(xφ(y)−1)。
朴素求 φ ( N ) \varphi(N) φ(N)
据唯一分解定理知 N = a 1 b 1 × . . . × a k b k N=a_1^{b_1}\times...\times a_k^{b_k} N=a1b1×...×akbk
也知 φ ( a 1 b 1 × . . . × a k b k ) = φ ( a 1 b 1 ) × . . . × φ ( a k b k ) \varphi(a_1^{b_1}\times...\times a_k^{b_k})=\varphi(a_1^{b_1})\times...\times\varphi(a_k^{b_k}) φ(a1b1×...×akbk)=φ(a1b1)×...×φ(akbk)
又知 φ ( a i b i ) = a i b i − a i b i − 1 \varphi(a_i^{b_i})=a_i^{b_i}-a_i^{b_i-1} φ(aibi)=aibi−aibi−1
那么 φ ( n ) = ( a 1 b 1 − a 1 b i − 1 ) × . . . × ( a k b k − a k b k − 1 ) \varphi(n)=(a_1^{b_1}-a_1^{b_i-1})\times...\times(a_k^{b_k}-a_k^{b_k-1}) φ(n)=(a1b1−a1bi−1)×...×(akbk−akbk−1)
把括号拆开 φ ( n ) = a 1 b 1 × ( 1 − 1 a 1 ) × . . . × a k b k × ( 1 − 1 a k ) \varphi(n)=a_1^{b_1}\times(1-\frac{1}{a_1})\times...\times a_k^{b_k}\times(1-\frac{1}{a_k}) φ(n)=a1b1×(1−a11)×...×akbk×(1−ak1)
最后 φ ( n ) = a 1 b 1 × . . . × a k b k × ( 1 − 1 a 1 ) × . . . × ( 1 − 1 a k ) = N × Π i = 1 N ( 1 − 1 a i ) \varphi(n)=a_1^{b_1}\times...\times a_k^{b_k}\times(1-\frac{1}{a_1})\times...\times(1-\frac{1}{a_k})=N\times\Pi_{i=1}^N(1-\frac{1}{a_i}) φ(n)=a1b1×...×akbk×(1−a11)×...×(1−ak1)=N×Πi=1N(1−ai1)
朴素代码
int ans = n;
for (int i = 2; i * i <= n; i++) {
while (n % i == 0) {
ans = ans / i * (i - 1);
n /= i;
}
}
if (n > 1) ans = ans / n * (n - 1);
筛法求 φ ( N ) \varphi(N) φ(N)
就是一边筛质数,一边求 φ \varphi φ,可以求出 1 − N 1-N 1−N 内的 φ \varphi φ,时间约 O ( N log N ) O(N\log N) O(NlogN)。
memset(a, true, sizeof(a));
k = 0, phi[1] = 1, a[1] = false;
for (int i = 2; i <= n; i++) {
if (a[i]) pri[++k] = i, phi[i] = i - 1;
for (int j = 1; j <= k && i * pri[j] <= n; j++) {
a[i * pri[j]] = false;
if (i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]];
else {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
}
}