欧拉函数

时间:2019-06-14
本文章向大家介绍欧拉函数,主要包括欧拉函数使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

欧拉函数

\(\varphi(x)\)表示\(x\)以内与\(x\)互质的个数
\(\varphi(x)=x*\prod\limits_{i=1}^n(1-\dfrac{1}{p_i})\) \(p_i\)为x的质因数
特殊的 \(\varphi(1)=1\)

其中\(p_1,p_2……p_n\)\(x\)的所有质因数(\(x\)是正整数)
那么,怎么理解这个公式呢?
对于\(x\)的一个质因数\(p_i\),因为\(x\)以内\(p_i\)的倍数是均匀分布的,所以\(x\)以内有\(\frac {1}{p_i}\)的数是\(p_i\)的倍数
对应的,有\(1-\dfrac {1}{p_i}\)的数不是\(p_i\)
同理,对于\(p_j\)\(1-\frac {1}{p_j}\)的数不是\(p_j\)的倍数
所以有\((1-\frac {1}{p_i})*(1-\frac {1}{p_j})\)的数既不是\(p_i\)的倍数,又不是\(p_j\)的倍数

积性函数

当有函数\(f(x)\)\(m\)\(n\)互质时,\(f(m)*f(n)=f(m*n)\)称为积性函数
对任意整数\(m\)\(n\)\(f(m)*f(n)=f(m*n)\)称为完全积性函数

欧拉函数的性质

  • 对于质数\(p\)\(\varphi(p)=p-1\)
    证明:这貌似不需要证明吧qwq

  • 对于质数p,\(\varphi(p^k)=p^k-p^{k-1}\)
    证明:\(\varphi(p^k)=p^k*(1-\dfrac{1}{p})\)

  • 欧拉函数是积性但飞完全积性函数,对于\(m\)\(n\)互质时,有\(\varphi(m)*\varphi(n)=\varphi(m*n)\)
    特殊的,\(m=2\)\(n\)为奇数,\(\varphi(m)*\varphi(n)=\varphi(n)\)
    证明:\(m\)\(n\)互质,说明没有公共质因数,\(m*n\)质因数为\(m\)的质因数+\(n\)的质因数

  • \(n>2\)时,\(\varphi(n)\)为偶数
    证明:有基本事实\(gcd(a,b)=1\) \(gcd(a,a-b)=1\),说明质因数都是成对出现的

  • 对于小于\(n\)且与\(n\)互质的数,总和=\(\varphi(n)*n/2\)
    证明:对于与\(n\)互质的数\(m\),有对立的\(n-m\)\(n\)互质,\(m\)\(n-m\)的平均数又为\(n/2\)\(\varphi(n)\)又为偶数

  • \(n=\sum\limits_{d|n}\varphi(d)\)
    设函数\(F(n)=\sum\limits_{d|n}\varphi(d)\)
    \(m\)\(n\)互质
    \(F(m)*F(n)=\sum\limits_{i|m}\varphi(i)*\sum\limits_{j|n}\varphi(j)\)
    \(=\varphi(i_1)*\varphi(j_1)+\varphi(i_1)*\varphi(j_2).....+\varphi(i_{km})*\varphi(j_{kn})\)
    \(=\varphi(i_1*j_1)+\varphi(i_1*j_2).....+\varphi(i_{km}*j_{kn})\) m与n互质,故因数也必全互质
    \(=\sum\limits_{k|m*n}\varphi(k)\) 可以发现,\(i_1*j_1,i_1*j_2.....i_{km}*j_{kn}\)这些数为\(n*m\)的因数
    \(=F(m*n)\)
    设合数\(n=p1^{k1}*p2^{k2}.....*pm^{km}\)\(F(n)=F(p1^{k1}*F(p2^{k2}).....*F(pm^{km}))\)
    利用性质2易证\(F(pm^{km})=pm^{km}\),则\(F(n)=p1^{k1}*p2^{k2}.....*pm^{km}=n\)

求欧拉函数

单个:\(2\)~\(\sqrt{(n)}\)扫一遍就好了,素数怎么求这个就怎么求
要是求<=n所有数的欧拉函数呢?
埃拉托斯特尼筛求欧拉函数 \(O(n(log(n))(loglogn))\)
就是普通的找质数,把倍数都筛一遍(质因数的贡献)

void euler(int n){
    for(int i=1;i<=n;++i) 
        phi[i]=i;
    for (int i=2;i<=n;i++)
        if (phi[i]==i)//i是质数
            for (int j=i;j<=n;j+=i)//把i的倍数筛一遍
                phi[j]=phi[j]/i*(i-1);
}

欧拉筛求欧拉函数 \(O(n)\)
先来了解一下欧拉筛

for(int i=2;i<=n;i++){
    if(!vis[i])//不是目前找到的素数的倍数 
        prime[cnt++]=i;//找到素数~ 
    for(int j=0;j<cnt&&i*prime[j]<=n;j++){
        vis[i*prime[j]]=true;//找到的素数的倍数不访问 
        if(i%prime[j]==0) 
            break;//关键!!!! 
    }
}

很多人对 $ if(i%prime[j]==0) break; $ 这一句都不太理解
找到一种很好的解释:
\(i\)\(prime[j]\)的倍数时,\(i=k*prime[j]\),如果继续运算 \(j+1\)\(i*prime[j+1]=prime[j]*k*prime[j+1]\)
这里\(prime[j]\)是最小的素因子,当\(i=k*prime[j+1]\)时会重复
这里是利用最小素因子优化,使得欧拉筛达到了优秀的线性\(O(n)\)
下面正式求欧拉函数啦

void euler(int n){
    phi[1]=1;//1要特判 
    for (int i=2;i<=n;i++){
    if(flag[i]==0)//这代表i是质数 
    {
        prime[++num]=i;
        phi[i]=i-1;
    }
    for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
    {
        flag[i*prime[j]]=1;//先把这个合数标记掉 
        if (i%prime[j]==0){
            phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
            break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
        }else 
            phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
    }
    }
}

原文地址:https://www.cnblogs.com/y2823774827y/p/10204471.html