题解:AcWing 873 欧拉函数

【题目来源】

AcWing:873 欧拉函数 - AcWing题库

【题目描述】

给定 \(n\) 个正整数 \(a_i\),请你求出每个数的欧拉函数。

【输入】

第一行包含整数 \(n\)

接下来 \(n\) 行,每行包含一个正整数 \(a_i\)

【输出】

输出共 \(n\) 行,每行输出一个正整数 \(a_i\) 的欧拉函数。

【输入样例】

3
3
6
8

【输出样例】

2
2
4

【核心思想】

  1. 问题分析:给定 \(n\) 个正整数 \(a_i\),求每个数的欧拉函数 \(\varphi(a_i)\)。欧拉函数 \(\varphi(n)\) 定义为小于等于 \(n\) 且与 \(n\) 互质的正整数的个数。这是一个经典的数论问题,核心在于利用质因数分解结合欧拉函数乘性公式进行计算。

  2. 算法选择

    • 试除法质因数分解:对每个 \(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)
  3. 关键步骤

    • 读取输入:整数 \(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 > 1\),说明剩余部分本身是一个质因数:
        • 更新 res = res / a_i * (a_i - 1)
      • 输出 res
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \cdot \sqrt{A})\)\(A\)\(a_i\) 的最大值。对每个数试除到平方根
    • 空间复杂度:\(O(1)\),除输入外仅使用常数额外空间
  5. 欧拉函数的核心思想

    • 定义\(\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
posted @ 2026-06-23 11:23  团爸讲算法  阅读(6)  评论(0)    收藏  举报