• 【数学】Euler函数


    Euler函数的定义:小于等于n的与n互质的正整数的个数,或者小于n的与n互质的自然数的个数。这两个结果都是指向 (gcd(0,1)=1) 也就是说 (varphi(1)=1)

    (varphi(p)=p-1)
    (varphi(p^k)=p^k-p^{k-1}=p^{k-1}(p-1)) 就是 (p^k) 里面去除掉所有的 (p) 的倍数。
    合数的情况使用积性函数的性质求出,或者用 (varphi(n)=nprodlimits_{t=1} (1-frac{1}{p_t})) 也就是n乘以1-每种质数的倒数。

    事实上,设 (n=prodlimits_{t=1}p_t^{k_t}) ,则 (varphi(n)=prodlimits_{t=1}varphi(p_t^{k_t})=prodlimits_{t=1} p_t^{k_t} frac{p_t-1}{p_t}=nprodlimits_{t=1}frac{p_t-1}{p_t})

    Euler函数可以用来给Fermat小定理升级成Euler定理

    (gcd(a,m)=1) ,则 (a^{varphi(m)} equiv 1 (mod m))

    Euler函数是积性函数。

    Dirichlet卷积

    (n=sum_{d|n}varphi(d))

    也就是每个数=它所有因子的Euler函数之和。

    注意积性函数的Dirichlet卷积也是积性函数,同时,Dirichlet卷积是积性函数的函数自己也是积性函数。

    质因数分解法求Euler函数

    const int MAXN = 1e6 + 10;
    int p[MAXN], ptop;
    int pm[MAXN];
    
    void sieve(int n) {
        pm[1] = 1;
        for(int i = 2; i <= n; ++i) {
            if(!pm[i])
                p[++ptop] = i, pm[i] = i;
            for(int j = 1; j <= ptop; ++j) {
                int t = i * p[j];
                if(t > n)
                    break;
                pm[t] = p[j];
                if(i % p[j])
                    ;
                else
                    break;
            }
        }
    }
    
    int phi(int n) {
        int res = n;
        for(int i = 1; p[i]*p[i] <= n; ++i) {
            if(n % p[i] == 0) {
                res = res / p[i] * (p[i] - 1);
                while(n % p[i] == 0)
                    n /= p[i];
            }
        }
        if(n > 1)
            res = res / n * (n - 1);
        return res;
    }
    

    时间复杂度为 (O(sqrt{n})) 预处理质数,然后 (O(frac{sqrt{n}}{log n})) 单次求解Euler函数。

    无论如何都要先筛质数,省掉这个log。

    线性筛法求Euler函数

    const int MAXN = 1e6 + 10;
    int p[MAXN], ptop;
    int pm[MAXN], pk[MAXN], phi[MAXN];
    
    void sieve(int n) {
        memset(pm, 0, sizeof(pm[0]) * (n + 1));
        ptop = 0, pm[1] = 1, pk[1] = 1, phi[1] = 1;
        for(int i = 2; i <= n; ++i) {
            if(!pm[i]) {
                p[++ptop] = i, pm[i] = i;
                pk[i] = i, phi[i] = i - 1;
            }
            for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; ++j) {
                pm[t] = p[j];
                if(i % p[j]) {
                    pk[t] = pk[p[j]];
                    phi[t] = phi[i] * phi[p[j]];
                } else {
                    pk[t] = pk[i] * p[j];
                    phi[t] = (pk[t] == t) ? t - t / p[j] : phi[t / pk[t]] * phi[pk[t]];
                    break;
                }
            }
        }
    }
    

    杜教筛求Euler函数前缀和

  • 相关阅读:
    【回顾整理】HTML+CSS个的两个实战项目
    【转】tkinter实现的文本编辑器
    迟到的tkinter---学校选课刷屏器
    调用有道翻译API
    【leetCode】3Sum Closest
    【LeedCode】3Sum
    【LeedCode】String to integer(atoi)
    【LeetCode】Reverse digits of an integer
    前端工程师必备PS技能
    【LeetCode】Add Two Numbers
  • 原文地址:https://www.cnblogs.com/purinliang/p/14288971.html
Copyright © 2020-2023  润新知