欧拉函数

是正整数,定义 为不超过 而与 互素的正整数的个数。

  • 例:.

从素因子的角度看互素

一个数与 互素也就是说它没有 的素因子。

是正整数, 无平方因子,我们不妨定义 为不超过 而与 互素的数的个数。

于是有 .

是素数,则

又设 是正整数,则

还有

用容斥原理计算

的素因子有 ,根据容斥原理, 中与 互素的数的个数等于

于是得

是积性函数

若正整数 互素,则 .

计算

进行素因子分解,找出 的全部素因子
根据 来计算 .

int phi(int n) {
    int ans = n;
    for (int i = 2; i * i <= n; i++) {
        int cnt = 0;
        while (n % i == 0) {
            n /= i;
            cnt++;
        }
        if (cnt)
            ans -= ans / i;
    }
    if (n > 1)
        ans -= ans / n;
    return ans;
}

设正整数 是素数。

  • ,则
  • ,则

根据这个性质,我们可以利用素数筛法计算

用埃氏筛法计算

vector<int> phi_table(int n) {
    vector<int> phi(n + 1);
    phi[1] = 1;
    vector<bool> vis(n + 1);
    for (int i = 2; i <= n; i++)
        if (!vis[i]) // i是素数
            for (int j = 1; j * i <= n; j++)
                if (!vis[j * i]) {
                    phi[j * i] = phi[j] * (j % i ? i - 1 : i);
                    vis[j * i] = true;
                }
    return phi;
}

精简写法:

vector<int> phi_table(int n) {
    vector<int> phi(n + 1);
    phi[1] = 1;
    for (int i = 2; i <= n; i++)
        if (phi[i] == 0) // i是素数
            for (int j = 1; j * i <= n; j++)
                if (phi[j * i] == 0)
                    phi[j * i] = phi[j] * (j % i ? i - 1 : i);
    return phi;
}

用线性筛法计算

vector<int> phi_table(int n) {
    vector<int> phi(n + 1);
    phi[1] = 1;
    vector<int> primes;
    for (int i = 2; i <= n; i++) {
        if (phi[i] == 0) { // i是素数
            primes.push_back(i);
        }
        for (int p : primes) {
            if (p * i > n)
                break;
            if (i % p == 0) {
                phi[p * i] = p * phi[i];
                break;
            } else {
                phi[p * i] = (p - 1) * phi[i];
            }
        }
    }
    return phi;
}

欧拉定理

是正整数, 是整数, 互素。那么

是素数时,欧拉定理就是费马小定理。