欧拉函数求解(因数分解和线性筛)

C++

欧拉函数及其简略证明

/*
 * 欧拉函数
 *
 * 定义:
 *   互质定义:
 *      互质是公约数只有1的两个整数,叫做互质整数。公约数只有1的两个自然数,叫做互质自然数。
 *   欧拉函数定义:
 *      在 1 ~ N 中和 N 互质的数的个数被称为欧拉函数,记作 phi(N)。
 *
 *   欧拉函数普通解法
 *      计算 N 的欧拉函数,使用欧几里得算法查看 1 ~ N 中的数字谁和 N 互质。
 *
 *   排除法推公式:
 *      N 质因数分解后可得:
 *          N = p_1 ^ a_1 * p_2 ^ a_2 * ... * p_k ^ a_k
 *      那么利用排除法,1 ~ N 中和 N 互质的数的个数为:
 *          N - N / p_1 - N / p_2 - ... - N / p_k
 *            + N / (p_1) ...
 *          = N * (1 - (1 / p_1) * (1 - (1 / p_2) * ... * (1 - (1 / p_k))
 *      同时可以看出,她和我们算数基本定理组成的素数有关,借助素数的递归关系,在线性筛的过程中求解
 *          有点向容斥定理那里走
 *
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int N = 1000010;
int n;
bool st[N];
int phi[N];


long long seive_get_phi(int n) {
    phi[1] = 1;
    memset(st, false, sizeof st);
    vector<int> primes;

    for (int i = 2; i <= n; i ++ ) {
        if (st[i] == false) {
            primes.push_back(i);
            phi[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ ) {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0) {       // 注意这里的判断挺有意思
                phi[i * primes[j]] = phi[i] * (primes[j]);
                break;
            } else {
                phi[i * primes[j]] = phi[i] * (primes[j] - 1);
            }
        }
    }

    long long res = 0;
    for (int i = 1; i <= n; i ++ ) {
        res += phi[i];
//        printf("i=%d, phi=%d\n", i, phi[i]);
    }
    return res;

}

int get_phi(int x) {
    vector<int> primes;
    int res = x;
    for (int i = 2; i <= x / i; i ++ ) {
        if (x % i == 0) {
            primes.push_back(i);
            while (x % i == 0) {
                x /= i;
            }
        }
    }

    if (x != 1) {
        primes.push_back(x);
    }


    for (int i = 0; i < primes.size(); i ++ ) {
        res = res - res / primes[i];    // res / primes[i] 一定是整数,自己可以证明的
    }
    return res;
}


int main()
{
    scanf("%d", &n);
    printf("%lld\n", seive_get_phi(n));

    return 0;
}

posted @ 2022-06-28 21:11  lucky_light  阅读(170)  评论(0编辑  收藏  举报