单个筛欧拉函数由欧拉函数公式直接在给n分解质因数时连乘就好
代码
int phi(int n)
{
int res=n,a=n;
for(int i=2;i*i<=a;i++)
{
if(a%i==0)
{
res=res/i*(i-1);//先除后乘防止溢出
while(a%i==0) a/=i;
}
}
if(a>1) res=res/a*(a-1);
return res;
}
先说一个近似线性筛的筛法
void Euler()
{
phi[1]=1;
for(int i=2;i<M;i++)
if(!phi[i])//没有被筛过说明是质数
for(int k=i;k<M;k+=i)
{
if(!phi[k]) phi[k]=k;
phi[k]=phi[k]/i*(i-1);//欧拉函数公式的实现
}
return ;
}
线性筛欧拉函数建立在线性筛素数的基础之上
重要性质:若i%p=0,p是素数,那么φ(i*p)=φ(i)*p,若i%p!=0,p是素数,那么φ(i*p)=φ(i)*(p-1)
证明(该证明可能存在错误):当i%p=0时,若GCD(a,b)=1,则GCD(a+b,b)=1,由此可以得出,将φ(i)中的数每个加i,则会得到另外φ(i)个数,若以此类推,累加(p-1)次,则一共有p*φ(i)个数与i互质,因为p是i的质因子,所以与i互质的数必定与i*p互质,所以φ(i*p)=φ(i)*p;当i%p!=0时,发现i,p互质,且p为素数,所以φ(p)等于p-1,由积性函数性质可得φ(i*p)=φ(i)*φ(p)=φ(i)*(p-1)
代码
void getphi()
{
int vis[M],phi[M],pri[M],tot;
for(int i=2;i<=n;i++)
{
if(!vis[i])//先判断i是不是素数
{
pri[++tot]=i;
phi[i]=i-1;//当 i 是素数时小于i的所有大于零的数都和i互素
}
for(int k=1;k<=tot;k++)
{
if(i*pri[k]>M) break;
vis[i*pri[k]]=1;//按照筛素数,筛掉i的倍数
if(i%pri[k]==0)//如果有一个质数是i的因子,那么phi(i*pri[k])=phi(i)*pri[k]
{
phi[i*pri[k]]=phi[i]*pri[k];break;
}
else phi[i*pri[k]]=phi[i]*(phi[pri[k]]);
//利用了欧拉函数的积性,两个数互质,那么phi(i*k)=phi(i)*phi(pri[k])
}
}
}