Post

欧拉函数

欧拉函数

在数论领域中,欧拉函数是一种重要的概念,它在解决许多数学问题和密码学中起着关键的作用。本文将介绍欧拉函数的定义、性质、求法 以及一些常见的应用,帮助读者更好地理解和应用欧拉函数。

欧拉函数的定义

欧拉函数,也称为欧拉降幂函数,是指小于或等于正整数 $n$ 的数中与 $n$ 互质 的数的个数。 欧拉函数通常用符号 $\phi(n)$ 表示。

欧拉函数的性质

  • 若 $n$ 为质数,则 $\phi(n) = n - 1$,因为质数与小于它的所有数都互质。
  • 若 $m$ 和 $n$ 互质,则 $\phi(mn) = \phi(m) * \phi(n)$,这是欧拉函数的积性性质。
  • 对于任意正整数n,有 $\sum_{d \mid n} \phi(d) = n$,其中 $d$ 是 $n$ 的正因子。

欧拉函数的计算方法

对于给定的正整数 $n$,可以通过分解质因数的方法来计算 $\phi(n)$。假设 $n$ 的质因数分解为 ${p_1}^{a_1} \times {p_2}^{a_2} \times … \times {p_k}^{a_k}$,则有 \(\phi(n) = n \times \prod (1 - \dfrac{1}{p_i})\)

借助欧拉筛求一段数的欧拉函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>
using namespace std;
const int M = 2e5 + 5;
int minp[M], phi[M];
vector<int> primes;
int main() {
    for (int i = 2; i <= 2e5; i++) {
        if (!minp[i]) {
            minp[i] = i;
            phi[i] = i - 1;
            primes.push_back(i);
        }
        for (int p : primes) {
            if (1ll * p * i > 2e5) {
                break;
            }
            minp[p * i] = p;
            phi[p * i] = i % p == 0 ? phi[i] * p : phi[i] * (p - 1);
            if (minp[i] == p) {
                break;
            }
        }
    }
    return 0;
}

求一个数的欧拉函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int phi(int x) {
    int res = x;
    for (int i = 2;1ll * i * i <= x; i++) {
        if (x % i == 0) {
            while (x % i == 0) {
                x /= i;
            }
            res -= res / i;
        }
    }
    if (x != 1) {
        res -= res / x;
    }
    return res;
}

应用

P3601

一个比较板的欧拉函数题,不难发现其实只需要求一段数的欧拉函数就可以得到答案。那么只需要求出这些数的所有质因数。由于这些数可能很大,对于每个数用根号复杂度分解质因数是行不通的,考虑到这一段数的长度不超过 $10^6$,可以使用类似埃式筛的方法,对于所有不超过 $10^6$ 的质数(因为待求解的数不超过 $10^{12}$),考虑它们是否是这段数的质因数,向数段遍历一遍即可。最后如果这段数中的数没有变成 $1$,说明它们有一个大于 $10^6$ 的质因数,也就是它们现在的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <bits/stdc++.h>
using namespace std;
const int maxN = 1e6 + 5, mod = 666623333;
long long l, r, phi[maxN], num[maxN];
int minp[maxN];
vector<int> primes;
void init() {
    for (int i = 2; i <= 1e6; i++) {
        if (!minp[i]) {
            minp[i] = i;
            primes.push_back(i);
        }
        for (auto p : primes) {
            if (1ll * p * i > 1e6) {
                break;
            }
            minp[p * i] = p;
            if (minp[i] == p) {
                break;
            }
        }
    }
    for (int i = 0; i <= 1e6; i++) {
        phi[i] = 1;
    }
}
long long ceil(long long x, long long y) {
    return x % y == 0 ? x / y : x / y + 1;
}
int main() {
    init();
    cin >> l >> r;
    for (int i = 0; i <= r - l; i++) {
        num[i] = l + i;
    }
    for (auto p : primes) {
        for (int i = ceil(l, p), idx; i <= r / p; i++) {
            idx = 1ll * i * p - l;
            long long tmp = 1;
            num[idx] /= p;
            while (num[idx] % p == 0) {
                num[idx] /= p;
                tmp = tmp * p % mod;
            }
            phi[idx] = phi[idx] * tmp % mod * (p - 1) % mod;
        }
    }
    for (int i = 0; i <= r - l; i++) {
        if (num[i] != 1) {
            phi[i] = phi[i] * (num[i] - 1) % mod;
        }
    }
    long long res = 0;
    for (int i = 0; i <= r - l; i++) {
        res = (res + i + l - phi[i]) % mod;
    }
    cout << res;
    return 0;
}

CF776E

推导发现,答案实际上是对 $n$ 求 $\dfrac{k+1}{2}$ 次欧拉函数,n 为 $1$ 时欧拉函数恒为 $1$,不需要继续求下去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxN = 2e5 + 5, M = 1e6 + 5;
const int mod = 1000000007;
int minp[M];
vector<int> primes;
void init() {
    for (int i = 2; i <= 1e6; i++) {
        if (!minp[i]) {
            minp[i] = i;
            primes.push_back(i);
        }
        for (auto p : primes) {
            if (1ll * p * i > 1e6) {
                break;
            }
            minp[p * i] = p;
            if (minp[i] == p) {
                break;
            }
        }
    }
}
ll phi(ll x) {
    ll res = x;
    for (auto p : primes) {
        if (1ll * p * p > x) {
            break;
        }
        if (x % p == 0) {
            res = res / p * (p - 1);
        }
        while (x % p == 0) {
            x /= p;
        }
    }
    if (x > 1) {
        res = res / x * (x - 1);
    }
    return res;
}
int main() {
    init();
    ll n, k;
    cin >> n >> k;
    k = (k + 1) >> 1;
    for (ll i = 0; i < k && n > 1; i++) {
        n = phi(n);
    }
    cout << n % mod;
    return 0;
}
This post is licensed under CC BY 4.0 by the author.