【基础数论】欧拉函数

欧拉函数

欧拉函数就是指:对于一个正整数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本身)。

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

废话少说,先上代码:

int euler(int n)  
{  
    int ans=n;  
    for(int i=2;i*i<=n;i++){  
        if(n%i==0){  
            ans-=ans/i;  // 这一步就是对应欧拉函数的通式
            //这一个语句是为了保证完全消除我们刚才得到的那个i因子。确保我们下一个得到的i是n的素因子。
            while(n%i==0){  
                n/=i;  
            }  
        }  
    }  
    //这个语句是为了保证我们已经除完了n的所有的素因子,有可能还会出现一个我们未除的因子,
    //如果结尾出现n>1 ,说明我们还剩一个素因子木有除。
    if(n>1)ans-=ans/n;  
    return ans;  
}

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

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

我们先来一个最朴素的打表

void euler()
{
    p[1]=1;
    for(int i=2;i<=MAXN;i++){
        int n=i;
        p[i]=i;
        for(int j=2;j*j<=n;j++){
            if(n%j==0){
                p[i]=p[i]/j*(j-1);
                while(n%j==0) n=n/j;
            }
        }
        if(n>1) p[i]=p[i]/n*(n-1);
    }
    for(int i=2;i<MAXN;i++)
        p[i]+=p[i-1];
}

这种打表方法并不是很理想。。。。

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

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

void euler()  
{  
    E[1]=1;  
    for(int i=2;i<maxn;i++)  
        E[i]=i;  
    for(int i=2;i<maxn;i++){  
        if(E[i]==i)  
        for(int j=i;j<maxn;j+=i){  
            E[j]=E[j]/i*(i-1);  
        }  
    }  
}

第二种:

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

上述打表方法的思想和最初的是差不多的。但是它进行了优化,所以比较快。
我们逐步分析一下:

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章