蒟蒻最近准备狂补数学啦TAThtml
基于筛素数,能够同时快速求出欧拉函数。因而蒟蒻准备从这里入手,整理一下实现的思路。函数
传统筛素数的作法(埃式筛)是,利用已知的素数,去筛掉含有此质因子的合数,十分巧妙。因为不是本文的重点,就只贴一下代码吧spa
#include<cstdio> #include<cmath> #define R register int const int N=100000000,SQ=sqrt(N); bool f[N]; int main(){ R i,j; for(i=2;i<=SQ;++i){ if(f[i])continue; for(j=i<<1;j<N;j+=i)f[j]=1; } /*for(i=2;i<N;++i) if(!f[i])printf("%d\n",i);*/ return 0; }
复杂度不会证,不过较近似于线性(大概是\(O(n\log\log n)\)的样子)。code
实际上蒟蒻打了个表,N与筛的次数大概有这样的关系htm
为何是近似的呢?由于每一个合数会被其多个质因子都筛一遍,因此并非严格的。blog
因而咱们要想办法让每一个合数只被筛掉一次。如何实现呢?咱们可让每一个合数都只被其最小质因子筛掉(欧拉筛)。get
与上面相比,这种新的更加优秀的写法有了较大的变化。代码以下,可结合注释理解,也很少讨论。数学
#include<cstdio> #include<cmath> #define R register int const int N=100000000,B=N>>1; bool f[N]; int pr[B]; int main(){ R i,j,p=0; for(i=2;i<=B;++i){ if(f[i]) for(j=1;j<=p&&i*pr[j]<N;++j){ f[i*pr[j]]=1; if(!(i%pr[j]))break;//这一句话就是使得每一个合数只被最小质因子筛掉的关键 //简要解释一下,若是pr[j]|i,那么i就有一个质因子pr[j] //那么{i*pr[j+k],k∈N*}的最小质因子就是pr[j]而不是pr[j+k]了 } else{ pr[++p]=i; for(j=1;j<=p&&i*pr[j]<N;++j) f[i*pr[j]]=1;//i是质数,因此能够省掉上面那个判断,减少常数 } } /*for(i=2;i<N;++i) if(!f[i])printf("%d\n",i);*/ return 0; }
实际运行\(N=10^8\)比上面那种写法快一半。flash
对一个正整数\(x\)定义欧拉函数\(\phi(x)\),为\([1,x]\)中与\(x\)互质的整数个数。io
几个基本内容(下面定义\(p\)为质数):
这样的话,是否是能够像埃式筛同样,经过某个质数筛去质因子含这个数的合数的同时,计算出这个合数的欧拉函数值呢?好像是不行的,由于可能两个数的商的欧拉函数值还没求出来。
这时候,更好的欧拉筛又派上了用场。枚举\(x\)再枚举质数\(p\),这时候\(\phi(x)\)和\(\phi(p)\)确定都求出来啦,那么\(\phi(x*p)\)固然也就求出来啦。
#include<cstdio> #define R register const int N=1000001; int pr[N],phi[N]; bool f[N]; int main(){ R int n,i,j,k,p=0; phi[1]=1;//内容1 for(i=2;i<N;++i){ if(!f[i])phi[pr[++p]=i]=i-1;//内容2 for(j=1;j<=p&&(k=i*pr[j])<N;++j){ f[k]=1; if(i%pr[j])//内容3 phi[k]=phi[i]*(pr[j]-1); else{ phi[k]=phi[i]*pr[j]; break; } } } return 0; }