欧拉函数

欧拉函数

1、定义:用 \(\varphi (n)\) 表示的是小于等于 \(n\)\(n\) 互质的个数,比如说 \(\varphi(1) = 1、\varphi(2)=1\),当 \(n\) 为质数时,很显然 \(\varphi(n)=n-1\)

2、性质:

  • 欧拉函数是积性函数,即对于所有的 \(gcd(a,b)=1\),都有 \(\varphi(ab)=\varphi(a)\varphi(b)\) ;特别的,当 \(n\) 为奇数时,有 \(\varphi(2n)=\varphi(n)\varphi(2)=\varphi(n)\) ;另外还有个很重要的积性函数,即 \(id(n)=\sum_{d|n}\varphi(d)=n(莫比乌斯方面的知识)\)

  • \(n=p^k\),其中 \(p\) 为质数,那么 \(\varphi(n)=p^{k}-p^{k-1}\)

  • 有唯一分解定理得:对于任意的 \(n\) 都能写成 \(n=\prod_{i=1}^{s}p_i^{k_i}\),其中 \(p_i\) 为质数,有 \(\varphi(n)=n\prod_{i=1}^{s}\frac{p_i-1}{p_i}\) ,推理过程就是利用积性函数的性质推理的。

3、质因数分解求欧拉函数值:\(O(\sqrt n)\)

template<typename T>
struct getphi{
    inline T calc(T x) {
        T ans = x;
        for (T i = 2; i <= x / i; i++) {
            if (x % i == 0) {
                ans = ans / i * (i - 1);
                while (x % i == 0) x /= i;
            }
        }
        if (x > 1) ans = ans / x * (x - 1);
        return ans;
    }
};

getphi<i64> ph;

4、优化版本后的求解:比前面的时间复杂度来的更低

template<typename T>
struct pre{
    int N;
    vector<T> preim;
    vector<T> a;
    pre(int N_) : a(N_ + 1) {
        N = N_;
        for (T i = 2; i <= N; i++) {
            if (!a[i]) {
                a[i] = i;
                preim.push_back(i);
            }
            for (auto p : preim) {
                if (i * p > N) break;
                a[i * p] = p;
                if (a[i] == p) {
                    break;
                }
            }
        }
    }
    
    inline bool ispreim(T x) {
        return (a[x] == x && x != 0);
    }
};

pre d(100000);

template<typename T>
struct getphi{
    inline T calc(T x) {
        T ans = x;
        for (auto p : d.preim) {
            if (p * p > x) break;
            if (x % p == 0) {
                ans = ans / p * (p - 1);
                while (x % p == 0) x /= p;
            }
        }
        if (x > 1) ans = ans / x * (x - 1);
        return ans;
    }
};

getphi<i64> ph;

5、线性筛求解:\((积性函数)\) 线性预处理欧拉函数,时间复度为:\(O(n)\)

template<typename T>
struct getphi{
    int N;
    vector<T> preim;
    vector<T> a;
    vector<T> phi;
    getphi(int N_) : a(N_ + 1), phi(N_ + 1) {
        N = N_;
        phi[1] = 1;
        for (T i = 2; i <= N; i++) {
            if (!a[i]) {
                a[i] = i;
                phi[i] = i - 1;
                preim.push_back(i);
            }
            for (auto p : preim) {
                if (i * p > N) break;
                a[i * p] = p;
                if (a[i] == p) {
                    phi[i * p] = phi[i] * p;
                    break;
                }
                phi[i * p] = phi[i] * phi[p];
            }
        }
    }
};
posted @ 2024-08-30 21:13  grape_king  阅读(128)  评论(0)    收藏  举报