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

      欧拉函数,又称为Euler's totient function,在程序编辑中有很大的用途,所以在此总结一下。

    欧拉函数定义

      少于或等于n的数中与n互质的数的数目。

    欧拉函数求法

      因为任意正整数都可以唯一表示成如下形式: 

        n=p1^a1*p2^a2*……*pi^ai  

      可以推出:Eular(n)=n*(1-1/p1)*(1-1/p2)....(1-1/pi);

      因为对于每一个质因子,比如2,那么在小于n的数中,与n不互质的,与其公约数是2的倍数的占其1/2,所以乘上1/2就是剩下与n公约数不含2的,然后依次类推,对于每个n的约数,乘上(pi-1/pi),最后的答案就是欧拉函数值了。

    欧拉函数代码

      欧拉函数在程序语言中,有两种求法,一种是按照定义求出单个的欧拉函数,一种是求出一定范围内所有的欧拉函数。

    单个欧拉函数 》

    int Eular(int n){
        int ret=1,i;
        for(i=2;i*i<=n;i++)
        if(n%i==0){
            n/=i,ret*=i-1;
            while(n%i==0)n/=i,ret*=i;
        }if(n>1) ret*=n-1;
        return ret;
    }
    

      也许对于这个程序一开始看会有些迷糊,为什么没有按照定义乘上用n乘上(pi-1/pi)呢?因为一开始ret是赋值为1而不是n,那么就省去了除法的部分,而直接乘上pi-1即可。

    筛法求欧拉函数 》

     for(i=1;i<=maxn;i++) phi[i]=i;
     for(i=2;i<=maxn;i+=2) phi[i]/=2;
     for(i=3;i<=maxn;i+=2)if(phi[i]==i){
         for(j=i;j<=maxn;j+=i)phi[j]=phi[j]/i*(i-1);
     }
    

      对于筛法求素数,想必大家已经非常地熟悉,那么筛法求欧拉函数也是同样的原理,对于每个质因子pi,要乘上(pi-1/pi),那么最后phi数组就是答案了。

    欧拉函数的应用

    HDU 1286 找新朋友 欧拉函数模板题

    题目大意:求一个小于一个数与其互质的数的个数

    题解:欧拉函数的定义,直接应用。

    #include <cstdio>
    int eular(int n){
        int ret=1,i;
        for(i=2;i*i<=n;i++)
        if(n%i==0){
            n/=i,ret*=i-1;
            while(n%i==0)
            n/=i,ret*=i;
        }
        if(n>1) ret*=n-1;
        return ret;
    }
    int main(){
        int n;
        scanf("%d",&n);
        while (scanf("%d",&n)!=EOF) printf("%d
    ",eular(n));
        return 0;   
    }

    HDU 2824 The Euler function  筛法求欧拉函数

    题目大意:求a到b范围的欧拉函数的和。

    题解:筛法就欧拉函数。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn=3000005;
    long long phi[maxn];
    int main(){
        int i,j,a,b;
        for(i=1;i<=maxn;i++) phi[i]=i;
        for(i=2;i<=maxn;i+=2) phi[i]/=2;
        for(i=3;i<=maxn;i+=2)if(phi[i]==i){
          for(j=i;j<=maxn;j+=i)
            phi[j]=phi[j]/i*(i-1);
        }
        while(scanf("%d%d",&a,&b)!=EOF){
            long long ans=0;
            for(i=a;i<=b;i++)ans+=phi[i];
            cout<<ans<<endl;
        }
        return 0;
    }

    HDU 1787 GCD Again  欧拉函数求补集

    题目大意:求小于n的gcd(i,n)大于1的个数

    题解:欧拉函数直接求gcd(i,n)==1的个数  用n减即可

    #include <cstdio>
    int Eular(int n){
        int ret=1,i;
        for(i=2;i*i<=n;i++)
        if(n%i==0){
            n/=i,ret*=i-1;
            while(n%i==0)n/=i,ret*=i;
        }
        if(n>1) ret*=n-1;
        return ret;
    }
    int main(){
        int n; 
        while(scanf("%d",&n),n!=0)printf("%d
    ",n-Eular(n)-1);
        return 0;
    }

    HDU 3501 Calculation 2  欧拉函数性质

    题目大意:求小于n的与n不互质的数的和。

    题解:首先欧拉函数可以求出小于n的与n互质的数的个数,然后我们可以发现这样一个性质,当x与n互质时,n-x与n互质,那么所有小于n与n互质的数总是可以两两配对使其和为n,这也就是为什么当n大于2时欧拉函数都是偶数,知道这一点后,就可以计算出小于n与n互质的数的和了,那么不互质的和只要用总和来减就可以了。

    #include <cstdio>
    typedef long long LL;
    LL n,ans;
    LL Eular(LL n){
        LL ret=1;
        for(int i=2;i*i<=n;i++){
            if(n%i==0){
                n/=i,ret*=(i-1);
                while(n%i==0)n/=i,ret*=i;
            }
        }
        if(n>1)ret*=(n-1);
        return ret;
    }
    int main(){
        while(~scanf("%lld",&n)&&n){
            ans=n*(n+1)/2-n;
            ans-=Eular(n)*n/2;
            printf("%lld
    ",ans%1000000007);
        }return 0;
    }

    HDU 2588 GCD  欧拉函数求与某数最大公约数为定值的数的个数

    题目大意:给定N,M, 求1<=X<=N 且gcd(X,N)>=M的个数。

    题解:首先,我们求出数字N的约数,保存在约数表中,然后,对于大于等于M的约数p[i],求出Euler(n/p[i]),累计就是答案。因为对于每一个大于等于m的约数,GCD(N,t*p[i])=p[i]>=m(t与p[i]互质),所以n除以p[i]的欧拉函数的和就是答案。

    #include <cstdio>
    int T,cnt,p[10000],n,m,i;
    int Eular(int n){
        int ret=1;
        for(int i=2;i*i<=n;i++){
            if(n%i==0){
                n/=i,ret*=i-1;
                while(n%i==0)n/=i,ret*=i;
            }
        }
        if(n>1)ret*=(n-1);
        return ret;
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            int ans=cnt=0; 
            scanf("%d%d",&n,&m);
            for(i=1;i*i<n;i++)if(n%i==0)p[cnt++]=i,p[cnt++]=n/i;
            if(n%i==0)p[cnt++]=i;
            for(int i=0;i<cnt;i++)if(p[i]>=m)ans+=Eular(n/p[i]);
            printf("%d
    ",ans);
        }return 0;
    }

    HDU 4983 Goffi and GCD  欧拉函数求与某数最大公约数为定值的数的个数

    题目大意:给你N和K,问有多少个数对满足gcd(N-A,N)*gcd(N-B,N)=N^K。

    题解:由于 gcd(a, N) <= N,于是 K>2 都是无解,K=2 只有一个解 A=B=N,只要考虑K=1的情况就好了其实上式和这个是等价的gcd(A,N)*gcd(B,N)=N^K,我们枚举gcd(A,N)=g,那么gcd(B,N)=N/g。问题转化为统计满足 gcd(A, N)=g的A的个数。这个答案就是 ɸ(N/g),只要枚举 N 的 约数就可以了。答案是 Σɸ(N/g)*ɸ(g)(g|N)。

    #include <cstdio>
    typedef long long LL;
    const int MOD=1000000007;
    LL Eular(LL n){
        LL ret=1;
        for(LL i=2;i*i<=n;i++){
            if(n%i==0){
                n/=i,ret*=i-1;
                while(n%i==0)n/=i,ret*=i;
            }
        }if(n>1)ret*=(n-1);
        return ret;
    }
    int main(){
        int n,k;
        while(~scanf("%d%d",&n,&k)){
            if(n==1||k==2){puts("1");continue;}
            if(k>2){puts("0");continue;}
            LL ans=0;
            for(LL i=1;i*i<=n;i++)if(n%i==0){
                LL t=Eular(i)*Eular(n/i)%MOD;
                (ans+=t)%=MOD;
                if(i*i!=n)(ans+=t)%=MOD;
            }printf("%d
    ",(int)ans);
        }return 0;
    }
    
  • 相关阅读:
    【luogu P1343 地震逃生】 题解
    【luogu P3931 SAC E#1
    【luogu P3275 [SCOI2011]糖果】 题解
    【luogu P2947 [USACO09MAR]向右看齐Look Up】 题解
    【luogu P1456 Monkey King】 题解
    【luogu P3377 左偏树(可并堆)】 模板
    【luogu P1993 小K的农场】 题解
    Sqlmap注入Base64编码的注入点
    kali高速更新源以及主题修改方法
    DiscuzX3.1搬家全过程
  • 原文地址:https://www.cnblogs.com/forever97/p/3940874.html
Copyright © 2011-2022 走看看