0x31质数

质数

  若一个正整数无法被除了 1 1 1 和它自身之外的任何自然数整除,则称该数为质数(素数),否则称该正整数为合数,素数总是成对出现的。
  在整个自然数集合中,质数的数量不多,分布比较稀疏,对于一个足够大的整数 N N N,不超过 N N N 的质数大约有 N / I n N N/InN N/InN 个,即每 l n N lnN lnN 个数中大约有 1 1 1 个质数。
   0 0 0 1 1 1 不是素数也不是合数。

质数的判定

(1)试除法
  根据定义我们只需要扫描 2 2 2~ N \sqrt N N 之间的所有整数,依次检查它们能否整除 N N N,若都不能整除,则 N N N 是质数,否则为合数。这种方法称为试除法时间复杂度为 O ( N ) O(\sqrt N) O(N )。当然我们需要特判 0 0 0 1 1 1 这两个整数,它们即不是质数也不是合数。

//我们可以使用这个函数判断一个数是否为质数
bool isprime(int n){
	if(n<2)return false;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0)return false;
	}
	return true;
}

加速技巧:大于 4 4 4 的素数总是等于 6 x + 1 6x+1 6x+1 6 x − 1 6x-1 6x1

//加速后的判断函数
bool isPrime(int n){
	if(n<=3) return n>1;
	//不在6的倍数的两侧的数一定不是质数 
	if(n%6!=1 && n%6!=5) return false;
	for(int i=5; i<=sqrt(n); i+=6){
		if(n%i==0 || n%(i+2)==0) return false;
	}
	return true;
}

质数的筛选

  给定一个整数 N N N,求出 1 1 1~ N N N 之间所有的质数,称为质数的筛选问题。
(1) E r a t o s t h e n e s Eratosthenes Eratosthenes(厄拉托塞师)筛法
   E r a t o s t h e n e s Eratosthenes Eratosthenes 筛法基于:任意整数的 x x x 的倍数 2 x , 3 x , ⋯ 2x,3x,\cdots 2x,3x, 都不是质数。
  所以,我们可以从 2 2 2 开始,由从小到大扫描每个数 x x x,把它的倍数 2 x , 3 x , ⋯   , [ N / x ] ∗ x 2x,3x,\cdots ,[N/x]*x 2x,3x,,[N/x]x 标记为合数。当扫描到一个数时,若它尚未被标记,则它不能被 2 2 2~ x − 1 x-1 x1 之间的任何数整除,该数就是质数。
   E r a t o s t h e n e s Eratosthenes Eratosthenes 筛法的进行过程如下:
在这里插入图片描述
我们可以发现, 2 2 2 3 3 3 都会把 6 6 6 标记为合数。实际上,小于 x 2 x^2 x2 x x x 的倍数在扫描更小的数时就已经被标记过了。因此,我们可以对 E r a t o s t h e n e s Eratosthenes Eratosthenes 筛法进行优化,对于每个数 x x x,我们只需要从 x 2 x^2 x2 开始,把 x , ( x + 1 ) ∗ x , ⋯   , [ N / x ] ∗ x x,(x+1)*x,\cdots ,[N/x]*x x,(x+1)x,,[N/x]x 标记为合数即可。

void primes(int n){
	memset(v,0,sizeof(v));//合数标记 
	for(int i=2;i<=n;i++){
		if(v[i]) continue;
		cout <<i<<endl;//i是质数 
		for(int j=i;j<=n/i;j++) v[i*j]=1; 
	}
}

E r a t o s t h e n e s Eratosthenes Eratosthenes 筛法的时间复杂度为 O ( ∑ 质 数 p ≤ N N p ) = O ( N   l o g   l o g   N ) O(\sum_{质数p\leq N}\frac{N}{p})=O(N\ log\,log\ N) O(pNpN)=O(N loglog N)。该算法实现简单,效率非常接近线性,是算法竞赛中最常用的质数筛法。

(2)线性筛法

质因数分解

  任何一个大于 1 1 1 的正整数都能唯一分解为有限个质数的乘积,可写作:
N = p 1 c 1 p 2 c 2 ⋯ p m c m N=p_1^{c_1}p_2^{c_2}\cdots p_m^{c_m} N=p1c1p2c2pmcm
  其中 c i c_i ci 都是正整数, p i p_i pi 都是质数,且满足 p 1 < p 2 < ⋯ p m p_1<p_2<\cdots p_m p1<p2<pm

  结合质数判定的 “试除法” 合质数筛选的 “ E r a t o s t h e n e s Eratosthenes Eratosthenes” 筛法,我们可以扫描 2 2 2~ N \sqrt N N 的每个数 d d d,若 d d d 能整除 N N N,则从 N N N 中除掉所有的因子 d d d,同时累计除去的 d d d 的个数。
  因为一个合数的因子一定在扫描到这个合数之前就从 N N N 中被除掉了,所以在上述过程中能整除 N N N 的一定是质数。最终就得到了质因数分解的结果,易知时间复杂度为 O ( N ) O(\sqrt N) O(N )
  特别的,若 N N N 没有被任何 2 2 2~ N \sqrt N N 的数整除,则 N N N 是质数,无需分解。

void divide(int n){
	m=0;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0){//i是质数 
			p[++m]=i,c[m]=0;
			while(n%i==0) n/=i,c[m]++;
		}
	}
	if(n>1)//n是质数 
		p[++m]=n,c[m]=1;
	for(int i=1;i<=m;i++){
		cout<<p[i]<<"^"<<c[i]<<endl;
	}
}

附录

  • 质数的其他判定法(大素数)
      在质数的判定中,试除法作为最简单也最经典的确定性算法,是我们在算法竞赛中常用的方法。有一些效率更高的随机性算法,例如“Miller=Robbin”等,有较小的概率把合数错误判断为质数,但多次判定合起来的错误概率趋近于零。也可以使用费马小定理 x p = x ( m o d   p ) x^p=x(mod\ p) xp=x(mod p)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值