zoukankan      html  css  js  c++  java
  • 「欧拉函数」学习笔记

    欧拉函数$varphi(n)$表示整数$1到n$中与$n$互质的数的个数。

    特殊情况

    1. $varphi(1) = 1$

    2. 当$n$为素数时,$varphi(n) = n-1$.

    3. 若$n$是素数$p$的$k$次幂,$varphi(n) = varphi(p^k) = p^k - p^{k-1} = (p-1)p^{k-1}$

    (除掉$p$的倍数即可,由于$p^k = p^{k-1} * p$,故共有$p^{k-1}$个$p$的倍数)

    性质1. 当$m, n$互质时,$varphi(mn) = varphi(m)varphi(n)$

    这就是欧拉函数的积性性质。欧拉函数是积性函数

    设有质数$ p_1, p_2 $,则$ varphi(p_1^{k_1} * p_2^{k_2}) $按照刚才的方法,总数减去$p_1$的倍数与$p_2$的倍数,再加上重复减掉的$p_1, p_2$的公倍数。

    $p_1$的倍数有$ 1 * p_1, 2 * p_1, ... , p_1^{k_1 - 1} * p_2^{k_2} * p_1 $,总共有$p_1^{k_1 - 1} * p_2^{k_2}$个。

    同理$p_2$的倍数有$p_1^{k_1} * p_2^{k_2-1}$个。

    由于$p_1, p_2互质$,$lcm(p_1, p_2) = p_1 * p_2$,$p_1 * p_2$的倍数有$ 1 * p_1 * p_2, 2 * p_1 * p_2 , ... , p_1^{k_1-1} * p_2^{k_2-1} * p_1 * p_2$,总共有$p_1^{k_1-1} * p_2^{k_2-1}$个

    因此我们得到$ varphi(p_1^{k_1} * p_2^{k_2}) = p_1^{k_1} * p_2^{k_2} -  (p_1^{k_1 - 1} * p_2^{k_2}) - (p_1^{k_1} * p_2^{k_2-1}) + p_1^{k_1-1} * p_2^{k_2-1}$

    然后再按照刚才的思路,分开考虑:

    $varphi(p_1^{k_1}) = p_1^{k_1} - p_1^{k_1-1}$

    $varphi(p_2^{k_2}) = p_2^{k_2} - p_2^{k_2-1}$

    故$varphi(p_1^{k_1}) * varphi(p_2^{k_2}) = p_1^{k_1} * p_2^{k_2} -  (p_1^{k_1 - 1} * p_2^{k_2}) - (p_1^{k_1} * p_2^{k_2-1}) + p_1^{k_1-1} * p_2^{k_2-1}$

    这两个式子是一模一样的,所以$varphi(p_1^{k_1} * p_2^{k_2}) = varphi(p_1^{k_1}) * varphi(p_2^{k_2})$

    所以$varphi(mn) = varphi(n) * varphi(m)$

    性质2. 欧拉函数的通式 $varphi(n) = n * prodlimits_{i=1}^r frac{p_i-1}{p_i}$

    证明:刚才我们得到了$varphi(p^k) = (p-1)p^{k-1}$,又得到了欧拉函数的积性性质$varphi(mn) = varphi(n) * varphi(m)$,也可以以此类推三个,四个……

       因此对于任意一个$varphi(n)$,我们可以对$n$进行质因数分解:

          $n = p_1^{k_1}p_2^{k_2}...p_r^{k_r}$

       对于这个$n$,我们依然使用这个方法,得到$varphi(n) = varphi(p_1^{k_1})varphi(p_2^{k_2})...varphi(p_r^{k_r})$

       因此就得到了$varphi(n) = (p_1^{k_1}-p_1^{k_1-1}) * (p_2^{k_2}-p_2^{k_2-1}) ... (p_r^{k_r}-p_r^{k_r-1})$

        $varphi(n) = prodlimits_{i=1}^r p_i^{k_i-1}(p_i-1)$

             $  = prodlimits_{i=1}^r p_i^{k_i} * p_i^{-1}(p_i-1)$

              $ = n * prodlimits_{i=1}^r frac{p_i-1}{p_i}$

       因此我们得到通式$varphi(n) = n * prodlimits_{i=1}^r frac{p_i-1}{p_i}$

      有了通式,我们就可以求欧拉函数$varphi(n)$了:

    int a,b,n,phi[N];
    main(){
        n = r;
        if(n == 2){ printf("1"); return 0; }
        for(int i = 1; i <= n; ++i) phi[i] = i;
        for(int i = 2; i <= n; ++i){
            if(phi[i] != i) continue;
            for(int j = i; j <= n; j += i) phi[j] = phi[j]/i*(i-1);
        }
        printf("%lld", phi[n]);
        return 0;
    }

        以上代码复杂度是$O(n)$的,顺便充当筛素数了。如果$ phi[i]=i $则说明是素数。然后对$n$之内所有以$i$为因子的数都记性上述公式描绘的操作。注意到我们先做了$/i$,然后再做乘。这样是为了避免数据过大而造成数据丢失。

    性质3. $varphi(p * x) = varphi(x) * p    (p | x)$ (x, p为整数)

    证明:由通式可得 $varphi(p * x) = p * x * prodlimits_{i=1}^r frac{a_i-1}{a_i}$ 

       观察通式我们发现,一个数的欧拉函数其实只和其各个素因数的种类有关,并不关心每种素因数有几个。那么只需要证明$ varphi(x) =  x * prodlimits_{i=1}^r frac{a_i-1}{a_i}$,也就是 $a_1 ~ a_r$包含了$x$与$x*p$的所有种类的素因数 就好了。

       那么由于$p | x$,说明$p$是$x$的约数,所以$p$的所有约数必然包括在$x$之内,所以$x$的所有种类的素因数都是$p * x$的所有种类的素因数是必然的。

       所以我们可以继续推:

       $ varphi(p * x) =  x * p * prodlimits_{i=1}^r frac{a_i-1}{a_i}$

       $ varphi(p * x) =  varphi(x) * p$

    总结一下,当$p$为质数时:若$p|x$,可以利用性质5推得$varphi(p * x)$。否则$x \% p ≠ 0$,又因为$p$是质数,所以$x, p$一定互质,所以用性质6就可以推得$varphi(p * x)$。因此当$p$为质数时,无论如何都可以推得$varphi(p * x)$,因此我们可以利用在线性筛素数的基础上线性完成欧拉函数的求解。

    /*
     * phi[i]用来表示欧拉函数
     * isprime[i]用来记录i是否是质数 
     * p数组用来存质数 
     */
    int n,tot;
    int phi[N],isprime[N],p[N]; 
    int main(){
        n = r;
        phi[1] = 1;
        for(int i = 2; i <= n; ++i){
            if(!isprime[i]){
                p[++tot] = i;
                phi[i] = i-1;    //若i是质数,则根据特殊情况2, varphi(i) =  i-1
            }
            for(int j = 1; j <= tot; ++j){
                if(i * p[j] > n) break;  //越界 
                isprime[i * p[j]] = 1;   //存在因子i和p[j],故一定不是质数 
                if(i % p[j] == 0){
                    phi[i * p[j]] = phi[i] * p[j]; /*性质5*/
                    break;
                    /*p[j]是i的素因子之一。由于i % p[j] == 0,所以p[j]也是i的素因子之一。
                     *因为p数组是递增的,因此p[j+1] > p[j],而i内包括了p[j]。p[j]已经作为i * p[j]的素因子了,
                     *所以p[j+1]就一定不是它的最小素因子了。 
                     */
                } 
                else phi[i * p[j]] = phi[i] * (p[j] - 1);
                    /*利用性质6,p[j]是质数*/
            }
        }
        printf("%d",phi[n]);
        return 0;
    }
  • 相关阅读:
    CentOS 6.4下Squid代理服务器的安装与配置
    从C++到objectivec[转]
    在Objectivec里面使用property教程【转】
    Socket常用的数据结构【转】
    iOS 5 Storyboard 学习之 Tabbar Controller,Navigation Controller (1)
    Linux Socket编程(不限Linux)
    重要的套接字函数[转]
    HTTP,TCP/IP
    网络编程socket之bind函数[转]
    linux 下遍历目录中的目录项
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9314003.html
Copyright © 2011-2022 走看看