参考博客:https://blog.youkuaiyun.com/HandsomeHow/article/details/51325463
定义:欧拉函数是小于n的数中与n互质的数的数目。例如φ(8)=4,因为1,3,5,7均和8互质。
欧拉函数的通式为φ(x)=x (1-1/p1)(1-1/p2)…(1-1/pk):,其中pi表示x的质因数。特别声明,φ(1)=1。
注意:每种质因数只一个。比如12=223那么φ(12)=12*(1-1/2)*(1-1/3)=4。
其中还有比较特殊的几个。
- 若p为质数,n=pk ,则φ(n)=pk-pk-1 。
- 如果n是奇数,那么φ(2n)=φ(n)
- 如果n是质数,那么,φ(n)=n-1 ,即所有小于n的数都与他互质。
- φ(a*b)=φ(a)*φ(b)
- 如果i%p==0,那么,φ(i*p)=φ(i)*p;
计算时phi(x)=x(1-1/p1)…(1-1/pi)中的x(1-1/pi)可以转化为x/pi*(pi-1)用来避免小数的产生,同时先除后乘可以避免溢出。
单个欧拉函数
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)
{
phi[j]=phi[j]/i*(i-1);//把i的倍数更新掉
}
}
}
}
线性筛
思想:保证每个合数只会被他的最小之质因子筛去。
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]];//利用了欧拉函数是个积性函数的性质
}
}
}