欧拉函数
定义:对于一个正整数n,n的欧拉函数ϕ(n)\phi(n)ϕ(n),表示小于等于n与n互质的正整数的个数
性质
性质1:如果n是质数,那么ϕ(n)=n−1\phi(n)=n-1ϕ(n)=n−1,因为只有n本身与它不互质。
性质2:如果p,q都是质数,那么ϕ(p∗q)=ϕ(p)∗ϕ(q)=(p−1)∗(q−1)\phi(p*q)=\phi(p)*\phi(q)=(p-1)*(q-1)ϕ(p∗q)=ϕ(p)∗ϕ(q)=(p−1)∗(q−1).
性质2推导:p,2p,3p,....,(q−1)∗p有q−1个数整除p∗q,同理q,2q,3q,...,(p−1)∗q有p−1个数可以整除pq,再加上pq本身能整除pq,那么丢掉这些数剩余的数就与pq互质,一共有pq−(q−1+p−1+1)=(p−1)(q−1)。p,2p,3p,....,(q-1)*p有q-1个数整除p*q,同理q,2q,3q,...,(p-1)*q有p-1个数可以整除pq,再加上pq本身能整除pq,那么丢掉这些数剩余的数就与pq互质,一共有pq-(q-1+p-1+1)=(p-1)(q-1)。p,2p,3p,....,(q−1)∗p有q−1个数整除p∗q,同理q,2q,3q,...,(p−1)∗q有p−1个数可以整除pq,再加上pq本身能整除pq,那么丢掉这些数剩余的数就与pq互质,一共有pq−(q−1+p−1+1)=(p−1)(q−1)。
性质3:根据性质2得出,如果p是质数,那么ϕ(pk)=pk−pk−1\phi(p^k)=p^k-p^{k-1}ϕ(pk)=pk−pk−1
性质推导:p,2p,3p,...,pk−1p,一共pk−1个数能够整除pkp,2p,3p,...,p^{k-1}p,一共p^{k-1}个数能够整除p^kp,2p,3p,...,pk−1p,一共pk−1个数能够整除pk
那么丢到这些数,剩下的pk−pk−1p^k-p^{k-1}pk−pk−1就与pkp^kpk互质。
性质4:对于任意正整数n,ϕ(n)=n(1−1p1)(1−1p2)(1−1p3)....(1−1pn),其中p1,p2,p3,...,pn是n的质因子\phi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})(1-\frac{1}{p_3})....(1-\frac{1}{p_n}),其中p_1,p_2,p_3,...,p_n是n的质因子ϕ(n)=n(1−p11)(1−p21)(1−p31)....(1−pn1),其中p1,p2,p3,...,pn是n的质因子,这个性质可以由性质2和性质3联合推导出来,这里我就不推了,大家自行推导。
性质5:若a为质数,b mod a=0,ϕ(a∗b)=ϕ(b)∗a\phi(a*b)=\phi(b)*aϕ(a∗b)=ϕ(b)∗a
性质6:若a,b互质,ϕ(a∗b)=ϕ(b)∗ϕ(a)\phi(a*b)=\phi(b)*\phi(a)ϕ(a∗b)=ϕ(b)∗ϕ(a)
性质7:若n为一个正整数,那么∑d∣n=n,d∣n表示d整除n\sum_{d|n}=n,d|n表示d整除n∑d∣n=n,d∣n表示d整除n。
模板
求单个欧拉函数
代码:
单个欧拉函数公式
phi(n)=1*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)*....*(1-1/pn);
其中p1,p2,p3...pn是n的质因子
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
int main()
{
ll n;
scanf("%lld",&n);
ll ans=n;
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0)
{
n/=i;
}
}
}
if(n>1) ans=ans/n*(n-1);//说明还有一个质因数没算,不然的花n应该为1
printf("%lld",ans);
return 0;
}
通过欧拉筛求欧拉函数
#include<iostream>
#include<cstring>
using namespace std;
const int Maxn=1e7;
int phi[Maxn];//记录数的约数个数(欧拉函数)
bool vis[Maxn];//记录数字是否访问
int prime[Maxn];//保存素数
int main()
{
memset(vis,false,sizeof(vis));
memset(phi,0,sizeof(phi));
memset(prime,0,sizeof(prime));
int n;
scanf("%d",&n);
vis[1]=1;//1不是素数
for(int i=2;i<=n;i++)
{
if(!vis[i])//没有被访问,也就是没有被筛掉,说明是素数
{
vis[i]=!vis[i];
prime[++prime[0]]=i;
phi[i]=i-1;
}
for(int j=1;j<=prime[0]&&i*prime[j]<=n;j++)
{
vis[i*prime[j]]=true;
if(i%prime[j]==0)//a%b==0,那么phi[a*b]=b*phi[a]
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);//两者互素
}
}
printf("%d\n",prime[0]);
for(int i=1;i<=prime[0];i++)
{
printf("%d %d\n",prime[i],phi[prime[i]]);
}
return 0;
}
请关注我看更多数论分支知识体系讲解,也别忘点个赞额!