目录
- [1 基础知识](#1 基础知识)
- [2 模板](#2 模板)
- [3 工程化](#3 工程化)
1 基础知识
数a的欧拉函数 ϕ ( a ) \phi(a) ϕ(a):表示1~n中与n互质的数的个数。其中两个数互质,是指这两个数的最大公约数为1。
根据定义,我们可以写出如下方法,
cpp
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
int phi(int a) {
int res = 0;
for (int i = 1; i <= a; ++i) {
if (gcd(i, a) == 1) {
res += 1;
}
}
return res;
}
但存在更快的求解方法,见如下关键步骤:
- 对数a进行分解质因子操作。
a = p 1 α 1 ⋅ p 2 α 2 ⋯ p k α k a=p_1^{\alpha_1} \cdot p_2^{\alpha_2}\cdots p_k^{\alpha_k} a=p1α1⋅p2α2⋯pkαk
cpp
unordered_map<int,int> get_prime_divisors(int a) {
unordered_map<int,int> mp;
for (int i = 2; i <= a / i; ++i) {
if (a % i == 0) {
int s = 0;
while (a % i == 0) {
a /= i;
s++;
}
mp[i] = s;
}
}
if (a > 1) mp[a] = 1;
return mp;
}
- 计算数a的欧拉函数,
ϕ ( a ) = a ⋅ ( 1 − 1 p 1 ) ⋅ ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p k ) \phi(a)=a\cdot (1-\frac{1}{p_1}) \cdot (1-\frac{1}{p_2}) \cdots (1-\frac{1}{p_k}) ϕ(a)=a⋅(1−p11)⋅(1−p21)⋯(1−pk1)
cpp
int phi(int a, unordered_map<int,int> mp) {
int res = a;
for (auto [x, y] : mp) {
res = res / x * (x - 1);
}
return res;
}
可以将以上两步合并,请看如下代码,
cpp
int phi(int a) {
int res = a;
for (int i = 2; i <= a / i; ++i) {
if (a % i == 0) {
res = res / i * (i - 1);
while (a % i == 0) {
a /= i;
}
}
}
if (a > 1) {
res = res / a * (a - 1);
}
return res;
}
2 模板
cpp
int phi(int x)
{
int res = x;
for (int i = 2; i <= x / i; i ++ )
if (x % i == 0)
{
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
3 工程化
题目1:输入n个数,请分别求出它们的欧拉函数值。
cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
while (n--) {
int x;
cin >> x;
int res = x;
for (int i = 2; i <= x / i; ++i) {
if (x % i == 0) {
res = res / i * (i - 1);
while (x % i == 0) x /= i;
}
}
if (x > 1) res = res / x * (x - 1);
cout << res << endl;
}
return 0;
}