欧拉函数

242 阅读2分钟

题目描述

给定 nn 个正整数 aia_i,请你求出每个数的欧拉函数。

输入格式

第一行包含整数 nn

接下来 nn 行,每行包含一个正整数 aia^i

输出格式

输出共 nn 行,每行输出一个正整数 aia^i 的欧拉函数。

数据范围

1n1001≤n≤100,
1ai2×1091≤a_i≤2×10^9

输入样例:

3
3
6
8

输出样例:

2
2
4

题目分析

这是一道关于求解欧拉函数的问题,欧拉函数是数论中的一个很基础的概念。

首先我们来看一下欧拉函数的定义及求解方式:

我们将 1∼N 中与 N 互质的数的个数被称为欧拉函数,记为 ϕ(N)。

若在算数基本定理中,N=pa1pa2pamN=p^{a_1}p^{a_2}…p^{a_m}…,则我们不加证明的给出欧拉函数的求解方式:

ϕ(N) = N×p11p1×p21p2××pm1pmN×\frac{p_1−1}{p_1}×\frac{p_2−1}{p_2}×…×\frac{p_m−1}{p_m}…

关于欧拉函数的证明方式,我们一般采用容斥原理的方式,在这里我们不再展开证明,而更重于本题的解题步骤。

首先对于一个数 nn,我们要求取它的所有质数。这里我们采取试除法的方式,即从 22 开始枚举到 n\sqrt{n},对于能被当前 nn 整除的枚举数,需要将 nn 一直除以这个数一直到无法整除,并记录这个数,在模拟的过程中我们可以知道,这个数一定是一个质数,而在后续对更大的数的枚举过程中,一定不会枚举到一个合数(因为在之前枚举到这个合数的最小质因数时已经对 nn 进行了除法操作)。最终按要求求取答案即可。

由于每个数 xx 在最坏情况下会产生 x\sqrt{x} 次枚举,则最终时间复杂度为 O(nx)O(n\sqrt{x})

Accept代码

#include <iostream>
#include <vector>

using namespace std;

vector<int> v;

void phi(int n)
{
    int res = n;

    for (int i = 2; i <= n / i; i ++)
    {
        if (n % i == 0)
        {
            while (n % i == 0)
            {
                n /= i;
            }
            v.push_back(i);
        }
    }
    if (n > 1) v.push_back(n);

    for (auto i : v)
    {
        res = 1ll * res * (i - 1) / i;
    }

    cout << res << '\n';
    v.clear();
}

int main()
{
    int t;
    cin >> t;

    while (t --)
    {
        int a;
        cin >> a;

        phi(a);
    }

    return 0;
}