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

    原文:http://subscribe.mail.10086.cn/subscribe/readAll.do?columnId=563&itemId=3419270

    欧拉函数

    欢迎各位读者指出不足,谢谢~

    首先我们要知道欧拉函数是个什么东东?

    废话不多说~欧拉函数就是指:对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) 。


    欧拉函数的通式:φ(n)=n*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)…..(1-1/pn),其中p1, p2……pn为n的所有质因数,n是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)。

    对于上述的通式一定要牢记在心,因为这是计算欧拉函数最重要的一步。  切记切记~~~~

    好,最简单的,我们根据通式即可得 最简单的代码:

     
     1 int euler(int n)  {   
     2    int ans=n;     
     3    for(int i=2;i*i<=n;i++){ 
     4       if(n%i==0){      
     5           ans-=ans/i;    
     6           while(n%i==0){  
     7                 n/=i;     
     8          }    
     9       }    
    10   }      
    11 if(n>1)ans-=ans/n;  
    12     return ans; 
    13  }
    晦涩难懂一:代码中的 ans-=ans/i;  这一步就是对应欧拉函数的通式~还是应该比较容易看懂的吧?

    晦涩难懂二:while(n%i==0)   n/=i;    这一个语句是为了保证完全消除我们刚才得到的那个i因子。确保我们下一个得到的i是n的素因子。

    晦涩难懂三:if(n>1)ans-=ans/n;  这个语句是为了保证我们已经除完了n的所有的素因子,有可能还会出现一个我们未除的因子,如果结尾出现n>1 ,说明我们还剩一个素因子木有除。

     看懂上述代码的就可以去练练手了~ 推荐题目:HDOJ  1787   题解:点击打开链接

    但是我们一般做的题当然不会这么简单啊~~来点稍微难一点点的。。。

    如果我们要求的数比较多,如果一个一个求那么很容易就超时,所以我们自然而然就想到——打表。

    如果我们依照上述思想,来个最朴素的打表。

     1 void euler(){  
     2   p[1]=1;  
     3   for(int i=2;i<=MAXN;i++){  
     4       int n=i;     
     5       p[i]=i;      
     6      for(int j=2;j*j<=n;j++){  
     7           if(n%j==0){          
     8              p[i]=p[i]/j*(j-1);   
     9              while(n%j==0) n=n/j; 
    10            }   
    11      }     
    12     if(n>1) p[i]=p[i]/n*(n-1); 
    13    }  
    14   for(int i=2;i<MAXN;i++)  
    15       p[i]+=p[i-1];
    16 }
    这种打表方法并不是很理想。。。。

    下面推荐 两种较快的打表方法:

    ps:这种好像稍微快那么一点点~

     1 void euler()  {     
     2     E[1]=1;     
     3     for(int i=2;i<maxn;i++)    E[i]=i; 
     4     for(int i=2;i<maxn;i++){   
     5        if(E[i]==i)   
     6        for(int j=i;j<maxn;j+=i){     
     7          E[j]=E[j]/i*(i-1);  
     8         }   
     9    }
    10  }

    第二种:

    1 void euler()  {   
    2      for(int i=2;i<maxn;i++){   
    3        if(!E[i])   for(int j=i;j<maxn;j+=i){       
    4                           if(!E[j])E[j]=j;      
    5                          E[j]=E[j]/i*(i-1);    
    6                     }  
    7     } 
    8  }

    上述打表方法的思想和最初的是差不多的。但是它进行了优化,所以比较快。

    我们逐步分析一下:

    首先,在这里我们枚举的是素因子。因为素因子比较少,如果枚举素因子的话肯定会大大优化复杂度?

    那么,我们如何保证我们得到的就一定是个素因子呢?这就是我们if语句的作用,例如在第一种方法中,我们在第二个for 循环中就是把所有数,除以素因子。这样得到的复杂度一定比枚举每个数,然后找素因子(最开始那个打表法)这种打表要优化的多。


    推荐题目:HDOJ  2824   题解:点击打开链接


    在平时,我们做题,一般不会直接或者只是考察一个数的欧拉函数值。而是一些变形,或者是欧拉函数的一些性质。

    在这我总结了几个欧拉函数常用的性质,希望读者多多补充。

    欧拉函数性质(持续更新):

     ①N>1,不大于N且和N互素的所有正整数的和是 1/2*M*eular(N)。 推荐题目:HDOJ  3501   题解:点击打开链接

    ②若(N%a==0 && (N/a)%a==0) 则有:E(N)=E(N/a)*a;

    ③若(N%a==0 && (N/a)%a!=0) 则有:E(N)=E(N/a)*(a-1);

  • 相关阅读:
    如何改变Activity在当前任务堆栈中的顺序,Intent参数大全
    SQL删除重复记录,并只保留一条
    SpringCloud+Eureka+Feign+Ribbon+zuul的简化搭建流程和CRUD练习
    Spring Cloud Bus 消息总线
    Spring Cloud之Swagger集群搭建
    nginx-ZUUL集群
    spring boot swagger-ui.html 404
    jenkins 部署docker 容器 eureka 集群 完整配置 多台服务器
    Linux(Centos)之安装Nginx及注意事项
    Idea 导出Modules =>jar
  • 原文地址:https://www.cnblogs.com/mhpp/p/8117240.html
Copyright © 2011-2022 走看看