• 欧拉函数性质与求法 [数论][欧拉函数]


    n的欧拉函数值用符号φ(n)表示

    欧拉函数的定义是,对于一个正整数n,小于n且与n互质的数的数目(包括1,特殊地,φ(1)=1 )。

    设p1,p2,p3,...,pr为n的全部r个质因数,则有φ(n)=n*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)…..(1-1/pr)。

    显然,用这个方法来计算单个欧拉函数是可以求解的。

    附上代码:

     1 int get_phi(int x){
     2     int re=x;
     3     for(int i=2;i*i<=x;i++)
     4         if(x%i==0){
     5             re/=i;re*=i-1;
     6             while(x%i==0)
     7                 x/=i;
     8         }
     9     //仍有质因数?特判x=2及x=3的情况 
    10     if(x^1) re/=x,re*=x-1;
    11     return re;
    12 }

    这个求法的时间复杂度是O(√n)d的。

    但这个求法有弊端:

    * 对于大量需要计算的欧拉函数值,逐一分解n的时间复杂度显然是十分高的。

    在使用求解欧拉函数之前,介绍欧拉函数的几个性质:

    (1) 欧拉函数是积性函数,当正整数m,n互质时,满足φ(mn)=φ(m)φ(n)。

    (2) 当n为奇数时,有φ(2n)=φ(n)。

    (3) n=∑ d|n φ(d)    ( d|n )。

    (4) 对于给定的一个质数p,φ(p)=p -1。则对于正整数 n = p^k ,φ(n) = p^k - p^(k -1)。

    (5) 若(N % a == 0 && (N / a) mod a == 0) 则有:φ(N)=φ(N / a) * a。

    (6) 若(N % a == 0 && (N / a) mod a != 0)  则有:φ(N)=φ(N / a) * (a - 1)。 (a 为质数)

    主要利用以上性质(4)(5)(6),我们可以用递推的方法按以下步骤来打出欧拉函数表。

    (1) 记φ(1)=1。这是递推步骤吗。

    (2) 根据性质(4),对于质数i,可直接得φ(i)=i-1,把i放入质数表prime中。

    (3) 对于i,从头开始枚举质数(思考为什么枚举质数),根据性质(5)(6),当(i mod primej) != 0时,φ(i*primej) = φ(i)*(primej -1)

                                 当枚举到(i mod primej) == 0时,φ(i*primej) = φ(i)*(primej),并停止(思考为什么要停止),枚举下一个i。

    由此我们得到了打出欧拉函数表的主要代码(变量的定义不在这里展示)

     1     phi[1]=1;
     2     for(int i=2;i<=n;i++){
     3         if(!check[i]){
     4             prime[++cnt]=i;
     5             phi[i]=i-1;
     6         }
     7         for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
     8             check[i*prime[j]]=1;
     9             if(i%prime[j])  phi[i*prime[j]]=phi[i]*(prime[j]-1);
    10             else{
    11                 phi[i*prime[j]]=phi[i]*prime[j];
    12                 break;
    13             }
    14         }
    15     }

    可以简单地得知时间复杂度是线性的O(n)。

    利用打好的欧拉函数表,我们可以验证它的以上几个性质。


    性质(2)

    1     for(int i=n/2*2;i>1;i-=2)
    2         if((i/2)&1)
    3             printf("phi[%d] = %d = phi[%d/2] = phi[%d] = %d
    ",i,phi[i],i,i/2,phi[i/2]);

    example

    phi[38] = 18 = phi[38/2] = phi[19] = 18
    phi[34] = 16 = phi[34/2] = phi[17] = 16
    phi[30] = 8 = phi[30/2] = phi[15] = 8
    phi[26] = 12 = phi[26/2] = phi[13] = 12
    phi[22] = 10 = phi[22/2] = phi[11] = 10
    phi[18] = 6 = phi[18/2] = phi[9] = 6
    phi[14] = 6 = phi[14/2] = phi[7] = 6
    phi[10] = 4 = phi[10/2] = phi[5] = 4
    phi[6] = 2 = phi[6/2] = phi[3] = 2
    phi[2] = 1 = phi[2/2] = phi[1] = 1



    性质(3)

     1     for(int i=1;i<=n;i++){
     2         printf("%d = ",i);
     3         int temp=0;
     4         int j;
     5         for(j=1;j<=i;j++)
     6             if(i%j==0){
     7                 temp+=phi[j];
     8                 printf("phi[%d]( =%d ) ",j,phi[j]);
     9                 break;
    10             }
    11         for(j=j+1;j<=i;j++)
    12             if(i%j==0){
    13                 temp+=phi[j];
    14                 printf("+ phi[%d]( =%d ) ",j,phi[j]);
    15             }
    16         printf(" =%d
    ",temp);
    17     }

    example

    1 = phi[1]( =1 ) =1
    2 = phi[1]( =1 ) + phi[2]( =1 ) =2
    3 = phi[1]( =1 ) + phi[3]( =2 ) =3
    4 = phi[1]( =1 ) + phi[2]( =1 ) + phi[4]( =2 ) =4
    5 = phi[1]( =1 ) + phi[5]( =4 ) =5
    6 = phi[1]( =1 ) + phi[2]( =1 ) + phi[3]( =2 ) + phi[6]( =2 ) =6
    7 = phi[1]( =1 ) + phi[7]( =6 ) =7
    8 = phi[1]( =1 ) + phi[2]( =1 ) + phi[4]( =2 ) + phi[8]( =4 ) =8
    9 = phi[1]( =1 ) + phi[3]( =2 ) + phi[9]( =6 ) =9
    10 = phi[1]( =1 ) + phi[2]( =1 ) + phi[5]( =4 ) + phi[10]( =4 ) =10


  • 相关阅读:
    兼容ie6浏览器窗口四角固定背景代码
    实用的js判断浏览器类型及版本
    测试
    C#动态获取鼠标位置的颜色
    对指定的网页进行截图
    C#中使用 SendMessage 向非顶端窗体发送组合键
    ProtelDXP练习作品51单片机最小系统
    对非顶端窗口截图
    C#直接操作并口
    单片机实现的数字钟
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/7222440.html
Copyright © 2020-2023  润新知