📜  phi 函数 (n log (log(n))) - C++ (1)

📅  最后修改于: 2023-12-03 15:18:18.824000             🧑  作者: Mango

phi 函数 (n log (log(n))) - C++

Phi 函数是一个经典的数学函数,它表示小于等于 n 的正整数中有多少个与 n 互质。这个函数在数论中有着广泛的应用,例如用于 RSA 公钥加密算法的密钥生成。 在本篇文章中,我们将介绍 C++ 实现 phi 函数的一个高效算法,时间复杂度为 O(n log (log(n)))。

算法思路

phi 函数的一种经典定义是通过欧拉定理得到的: φ(n) = n * ∏(p|n) (1 - 1/p) 其中 p|n 表示 p 是 n 的质因子。这个公式比较直接,但是计算量比较大,需要对 n 的每个质因子都进行乘积运算。

然而,通过积性函数理论,我们可以发现 phi 函数是一个积性函数,这意味着我们可以将 n 拆分成质因子的乘积形式,然后根据积性函数的性质将 phi 函数的计算拆分成多个子问题的计算。具体来说,如果 n=p^k,则有: φ(n) = p^k - p^(k-1) 即,素数幂上的 phi 值只与素数本身有关系,而与其幂次无关系。因此,我们可以采用埃拉托色尼筛法的思想,从小到大遍历所有小于等于 n 的数,对于每个素数 p,我们将其直接计算出来,然后用它更新所有 p 的倍数的 phi 值。

这个思路的优点在于,我们只需要计算每个素数的 phi 值,然后将其扩展到所有素数的倍数上,时间复杂度就可以做到 O(n log (log(n)))。

代码实现

下面是 C++ 实现 phi 函数的代码,包含了上述算法思路的实现。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int N = 1e6;

int primes[N + 1], cnt;
int phi[N + 1];

int main() {
    for (int i = 2; i <= N; i++) {
        if (!phi[i]) {
            primes[++cnt] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= cnt && primes[j] * i <= N; j++) {
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            } else {
                phi[i * primes[j]] = phi[i] * (primes[j] - 1);
            }
        }
    }
    // 输出 phi 数组,测试正确性
    for (int i = 1; i <= 20; i++) {
        printf("phi(%d) = %d\n", i, phi[i]);
    }
    return 0;
}

这个代码中,我们使用了两个数组 primes 和 phi 分别记录了所有素数和 phi 函数的值,其中 primes 数组可以通过埃拉托色尼筛法生成,而 phi 数组则是通过上述算法思路计算得到的。可以看到,这个代码的时间复杂度是 O(n log (log(n))),非常高效。

总结

本篇文章介绍了 phi 函数的一个高效 C++ 实现算法,利用了积性函数和埃拉托色尼筛法的思想,时间复杂度为 O(n log (log(n)))。对于一些需要计算 phi 函数的算法,这种实现方法可以提高效率,也可以进一步扩展到计算一些其他积性函数的情况。