本章介绍关于素数的一些数论,限于篇幅不给出证实,须要证实的朋友自行相关证实。优化
什么是素数?只能被本身和1整除的数就是素数。spa
利用这个性质咱们很容易获得下面的素数判断方法。code
bool isPrime(int x){ if(x==1)return 0; for(int i=2;i*i<=x;i++) if(x%i==0)return 0; return 1; }
这里解释一下为何是i*i<=x,i*i<x转化一下就是i<=sqrt(x)。blog
想想,若是咱们枚举到sqrt(x)都没有找到能够被它整除的数,后面也就不可能有能够被它整除的数了,由于一个>sqrt(x)的数要是被x整除了,它的商确定是<sqrt(x)的,而咱们已经枚举过<=sqrt(x)的数了,里面没有,因此>sqrt(x)的约数也是不可能有的。ci
这种判断方法的时间复杂度是O(sqrt(n))的,空间复杂度是O(1)的。it
再给出一个判断方法,这个方法的时间复杂度大概是O(sqrt(n)/3)的,空间复杂度也是O(1)。io
bool isPrime(int x){ if(x==1)return false; if(x==2||x==3)return true; if(x%6!=1&&x%6!=5)return false; for(int i=5;i*i<=x;i+=6) if(x%i==0||x%(i+2)==0)return false; return true; }
证实被我吃了。class
而后就是几种素数的筛法了。咱们规定下文中讨论的[]为向下取整。效率
首先是著名的埃筛,Eratosthenes筛法。百度
埃筛基于这样一个想法:对于一个数x,它的倍数2x,3x,4x,5x...都不是质数。
因而,咱们从2开始从小到大扫描每一个数x,把它的倍数2x,3x,4x,...,[N/x]*x标记为合数。
当扫描到一个数时,若它未被标记为合数,则它就不能被2~x-1中的任何数整除,它就是质数。
可是咱们会发现,埃筛会重复标记一个数。好比8,它会被2标记,还会被4标记,这样影响了效率。
因而咱们考虑优化,对于每一个数,从x^2开始把x^2,(x+1)*x,...,[N/x]*x标记为合数。
给出代码:
int comp[maxn],prime[maxn]; //合数标记(composite),素数标记 void Eratothenes(int n){//筛到哪里
for(int i=2;i<=n;i++){ if(comp[i])continue; prime[i]=1;//i是质数 for(int j=i;j<=n/i;j++)comp[i*j]=1; } }
优化后的埃筛的时间复杂度是O(nloglogn),接近线性,并且很好写,推荐熟记。
那有没有线性筛呢,有,可是我的认为,会埃筛就够了,不必为了卡常写到线性。
想了解的能够自行百度。
接下来给出一些定理,仍是同样,不证。
1. 惟一分解定理
若整数x>=2,则x必定能够以惟一的形式表示成若干个素数的乘积。
能够写做:x=p1^c1*p2^c2*p3^c3*...*pm^cm。
其中,ci均为正整数且pi均为素数,知足p1<p2<...<pm
2. 威尔逊定理
没啥用的定理,若p为素数,则(p-1)! ≡ 1(mod p)。
3. 威尔逊定理的逆定理
若对于某一正整数p,有(p-1)! ≡ -1(mod p),则p为素数。
3. 费马定理
若p为素数,x为正整数,且x和p互质,则x^(p-1) ≡ 1(mod p)。
4. 费马小定理
若p为素数,则x^p ≡ x(mod p)。
还有一些东西:( ﹁ ﹁ ) ~→待填坑