zoukankan      html  css  js  c++  java
  • 欧拉函数

     

    在数论中,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目  

    用φ(n) 来表示欧拉函数,特别的是对于一个数n,1也是与n互质的,则 φ(1) = 1;

    欧拉函数的通式:$phi left( n ight) =ncdot left( 1-dfrac {1}{p_{1}} ight) .left( dfrac {1}{1-p_{2}} ight) cdot ldots cdot left( 1-dfrac {1}{p_{k}} ight)$

     对于公式的推导,只有感叹一句:欧拉牛逼!

    这里主要讲一下怎么转化为代码。首先要知道的是 p1,p2,... pk 都是 n 的质因数(不重复)

    例如 12 = 2 * 2 * 3,那么 p1 = 2, p2 = 3;

    则:φ(12) = 12 * (1 - 1/2) * (1 - 1/3) = 4;这四个数分别是 1,5,7,11 

    接下来考虑怎么求 φ(n),由于φ(n) = n * (1 - 1/p1)  *  (1 - 1/p2) .....  

                 我们设 ans = n,展开 n * (1 - 1/p1)  = ans * (1 - 1/p1) = ans - ans/p1,-->> ans = ans - ans/p1  由此类推我们可以得到递推公式:

                 ans = ans - ans/pi (pi 是 n 的质因数)

      接下来上代码:

      

      这只是对于求一个数的欧拉函数。复杂度是 $Oleft( log n ight)$ 的。

      那么如果我们要求的是 $left[ 1,n ight]$ 区间的欧拉函数的话,就需要更快的方法了。

      我这里介绍的是根据 欧拉筛来求欧拉函数,是线性的。如果对欧拉筛不懂的话,可以先去学习一波,不然不容易理解代码

      

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 const int N = 1e5 + 10;
     6 
     7 int phi[N], mark[N], prime[N];
     8 //phi 用来记录欧拉函数,mark来标记素数, prime来存素数
     9 int lenPrime = 0;
    10 
    11 void euler()
    12 {
    13     //1 要特判
    14     phi[1] = 1;
    15     memset(mark, 0, sizeof(mark));
    16     for(int i = 2; i < N; i++)
    17     {
    18         //如果 i 是素数
    19         if(mark[i] == 0)
    20         {
    21             phi[i] = i - 1; //素数的欧拉函数就是 自己 - 1
    22             prime[lenPrime++] = i;  //把素数记录下来
    23         }
    24         //循环条件 : j 就是遍历prime数组,i * prime[j] < N 也是显然易见的
    25         for(int j = 0; j < lenPrime && i * prime[j] < N; j++)
    26         {
    27             // i* prime[j] 是合数,所以标记为 1
    28             mark[i * prime[j]] = 1;
    29             if(i % prime[j] == 0)
    30             {
    31                 phi[i*prime[j]] = prime[j] * phi[i];
    32                 break;
    33             }
    34             else phi[i * prime[j]] = phi[i] * phi[prime[j]];
    35         }
    36     }
    37 }
    38 
    39 int main()
    40 {
    41     euler();
    42     for(int i = 1; i <= 20; i++)    printf("E[%d] = %d
    ", i, phi[i]);
    43     return 0;
    44 }

      

    这里主要对两个地方进行讲解:

      第一是 31行的:

       if(i % prime[j] == 0)  phi[i*prime[j]] = prime[j] * phi[i];

       我们设 a = i * prime[j] ;显然 prime[j] a 的一个质因子

       1.那么  a 的 其他质因子 显然 在 i 里,也就是说 a 的质因子 = i 的质因子 + prime[j]

       2.但由于 i % prime[j] == 0  ------>  prime[j] 也是 i 的 质因子

       综合 1 和 2 的结论 我们可以得出 a 的 质因子 = i 的质因子

       例如 当 i = 6,prime[j] = 2 时,i* prime[j] = 12; 显然 6 % 2 == 0 ,则 6 的质因子都是 12 的质因子。

       由欧拉函数 φ(i * prime[j]) = (prime[j] * i)* (1 - 1/p1) * (1 - 1/p2)....

                         = prime[j] * i * (1 - 1/p1) * (1 - 1/p2)......  //由于 p1,p2,....都是 i 的 质因子

                         =    prime[j] * φ(i )

      

      第二是 34 行的:

        这里我们需要知道 积性函数 : f(a*b) = f(a) * f(b) (a,b互质)  那么 f 这个函数就是一个积性函数

        欧拉函数也是一个积性函数    所以当 a,b 互质时 :φ(a * b)  = φ(a) * φ(b)  

      

    关于欧拉函数暂时就讲到这里.............

  • 相关阅读:
    【剑指offer】二叉搜索树与双向链表
    【剑指offer】复杂链表的复制
    【剑指offer】二叉树中和为某一值的路径
    2018.12.30 Intellij IDEA设置main方法自动补全
    2018.12.29 Spring FrameWork各个版本下载
    2018.12.26 Mac下的Eclipse在编辑Spring配置文件xml时自动提示类class包名配置
    2018.12.25 Spring中JDBCTemplate模版API学习
    2018.12.24 Spring中的aop演示(也就是运用aop技术实现代理模式)
    2018.12.22 Spring学习02
    2018.12.24 Ubuntu18.0.4 主题参考
  • 原文地址:https://www.cnblogs.com/nonameless/p/11750030.html
Copyright © 2011-2022 走看看