一 质数:
质数的分布密度:对于一个足够大的自然数N,不超过N的质数大约有N/ln(N)个,即每ln(N)个数中大约有1个质数。
1 质数的判定: 试除法
引理:若一个正整数N为合数,则存在一个能整除N的数T,其中2<=T<=
根据上述命题,我们只需扫描2~之间所有的整数,依次检查他们能否整除N,若都不能整除,则N是质数,否则N是合数。试除法的时间复杂度为O(
).当然,我们需要特判0,1他们既不是质数,也不是合数。
bool is_prime(int n){ if(n<2) return false; for(int i=2;i<=n/i;i++) if(n%i==0) return false; return true; }
2 质数的筛选:
给定一个整数N,求出1~N之间所有的质数,成为质数的筛选。
埃氏筛:
引理:任意整数x的倍数,2x,3x,4x,……都不是质数。
根据上述命题,我们可以从2开始,由小到大扫描每个数x,把它的倍数2x,3x……,标记为合数。当扫描到一个数时,若它尚未被标记,则它不能被2~x-1之间的任何数整除,该数就是质数。
另外,我们可以发现,扫描2和3时,都会把6标记为合数。实际上,小于的
的倍数在扫描更小的数时就已经被标记过了。因此,我们可以对埃氏筛进行优化,对于每个数x,我们只需要从
开始,把
,
,……,
标记为合数即可。
void get_prime(int n){ memset(st,0,sizeof(st)); cnt=0; for(int i = 2; i <= n; i ++){ if(!st[i]){//若没有被筛过,说明是质数 prime[cnt ++] = i; for(int j = i ; j <= n/i; j ++) st[i*j] = 1;//进行筛选i的整数倍 } } }
埃氏筛的时间复杂度氏O()(其中p是质数)=O(
).该算法实现简单,效率已经非常接近于线性。
线性筛:
即使在优化后(从开始),埃氏筛仍然会重复标记合数。例如12既会被2标记,又会被3标记,在标记2的倍数时。12=6*2,在标记3的倍数时,12=4*3,原因是我们没有确定出唯一的产生12的方式。
线性筛对于每个合数i*p,只会被它的最小质因子p筛一次,时间复杂度为O(n).
void get_prime(int n){ memset(st,0,sizeof(st)); for(int i = 2; i <= n; i ++){ if(!st[i]){//如果没有被筛过,说明是质数 prime[cnt ++] = i;//储存质数 } for(int j = 0; prime[j] <= n / i; j ++){ st[prime[j] * i] = 1;//prime[j]是合数i*prime[j]的最小质因子 if(i % prime[j] == 0) break; } } }
3 质因数分解:
引理:任何一个大于1的整数都能唯一分解为有限个质数的乘积,可写作:
……