题解:AcWing 873 欧拉函数
【题目来源】
AcWing:873 欧拉函数 - AcWing题库
【题目描述】
给定 \(n\) 个正整数 \(a_i\),请你求出每个数的欧拉函数。
【输入】
第一行包含整数 \(n\)。
接下来 \(n\) 行,每行包含一个正整数 \(a_i\)。
【输出】
输出共 \(n\) 行,每行输出一个正整数 \(a_i\) 的欧拉函数。
【输入样例】
3
3
6
8
【输出样例】
2
2
4
【核心思想】
-
问题分析:给定 \(n\) 个正整数 \(a_i\),求每个数的欧拉函数 \(\varphi(a_i)\)。欧拉函数 \(\varphi(n)\) 定义为小于等于 \(n\) 且与 \(n\) 互质的正整数的个数。这是一个经典的数论问题,核心在于利用质因数分解结合欧拉函数乘性公式进行计算。
-
算法选择:
- 试除法质因数分解:对每个 \(a_i\) 从 \(2\) 枚举到 \(\sqrt{a_i}\),逐个提取质因数
- 欧拉函数公式:若 \(n = p_1^{c_1} p_2^{c_2} \cdots p_k^{c_k}\),则 \(\varphi(n) = n \cdot \prod_{i=1}^{k} \left(1 - \frac{1}{p_i}\right) = \prod_{i=1}^{k} \frac{n}{p_i} \cdot (p_i - 1)\)。在分解过程中遇到质因数 \(p\) 时,直接更新结果
res = res / p * (p - 1)
-
关键步骤:
- 读取输入:整数 \(n\),以及 \(n\) 个正整数 \(a_i\)
- 计算欧拉函数(对每个 \(a_i\)):
- 初始化
res = a_i - 遍历 \(i\) 从 \(2\) 到 \(\lfloor \sqrt{a_i} \rfloor\):
- 若 \(a_i \bmod i == 0\),说明 \(i\) 是一个质因数:
- 更新
res = res / i * (i - 1)(对应因子 \((1 - 1/i)\)) - 将 \(a_i\) 中所有 \(i\) 的因子除尽(
while (a_i % i == 0) a_i /= i)
- 更新
- 若 \(a_i \bmod i == 0\),说明 \(i\) 是一个质因数:
- 若分解后 \(a_i > 1\),说明剩余部分本身是一个质因数:
- 更新
res = res / a_i * (a_i - 1)
- 更新
- 输出
res
- 初始化
-
时间/空间复杂度:
- 时间复杂度:\(O(n \cdot \sqrt{A})\),\(A\) 为 \(a_i\) 的最大值。对每个数试除到平方根
- 空间复杂度:\(O(1)\),除输入外仅使用常数额外空间
-
欧拉函数的核心思想:
- 定义:\(\varphi(n) = |\{ x \mid 1 \leq x \leq n, \gcd(x, n) = 1 \}|\),即与 \(n\) 互质的数的个数
- 乘性性质:若 \(\gcd(m, n) = 1\),则 \(\varphi(mn) = \varphi(m) \cdot \varphi(n)\)。这是欧拉函数能够分解计算的理论基础
- 质数幂公式:对于质数 \(p\) 和正整数 \(k\),\(\varphi(p^k) = p^k - p^{k-1} = p^{k-1}(p - 1)\)。因为 \(1\) 到 \(p^k\) 中不与 \(p^k\) 互质的数恰好是 \(p\) 的倍数,共 \(p^{k-1}\) 个
- 一般公式推导:由唯一分解定理和乘性性质,\(\varphi(n) = n \cdot \prod_{p|n} (1 - 1/p)\)。在代码中通过逐步除以质因数并乘回 \((p - 1)\) 来实现
- 与欧拉定理的关系:若 \(\gcd(a, n) = 1\),则 \(a^{\varphi(n)} \equiv 1 \pmod{n}\),这是 RSA 等加密算法的理论基础
- 适用于互质计数、模逆元存在性判断、循环群阶数计算、密码学等问题
【解题思路】

【算法标签】
欧拉定理
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 定义欧拉函数,计算小于等于n且与n互质的数的个数
int oula(int n)
{
int res = n; // 初始化结果为n
for (int i = 2; i <= n / i; i++) // 遍历从2到sqrt(n)的所有整数
{
if (n % i == 0) // 如果i是n的因子
{
res = res / i * (i - 1); // 更新结果,使用欧拉函数公式
while (n % i == 0) n /= i; // 将n中所有i的因子去除
}
}
if (n > 1) res = res / n * (n - 1); // 如果n大于1,说明n本身是一个质数,更新结果
return res; // 返回最终结果
}
int main()
{
int n;
cin >> n; // 读取输入的整数n,表示接下来要处理的数的数量
while (n--) // 循环n次
{
int a;
cin >> a; // 读取每个数a
cout << oula(a) << endl; // 计算并输出a的欧拉函数值
}
return 0; // 程序结束
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n; // 查询次数
cin >> n;
while (n--) // 处理每个查询
{
int a; // 输入的正整数
cin >> a;
int res = a; // 初始结果为a,即φ(a)的最大可能值
// 对a进行质因数分解
for (int i = 2; i <= a / i; i++) // 只检查到√a
{
// 如果i是a的质因数
if (a % i == 0)
{
// 欧拉函数公式: φ(n) = n * ∏(1 - 1/p)
// 这里用 res = res / p * (p-1) 来实现
res = res / i * (i - 1);
// 除去a中所有的i因子
while (a % i == 0)
{
a /= i;
}
}
}
// 如果a>1,说明a还有一个大于√a的质因数
if (a > 1)
{
res = res / a * (a - 1);
}
cout << res << endl; // 输出欧拉函数值
}
return 0;
}
【运行结果】
3
3
2
6
2
8
4
浙公网安备 33010602011771号