线性筛素数 证明详解

线性筛素数

代码实现:

typedef long long ll;     
const ll N = 200000;   
ll prime[N] = {0},num_prime = 0;  //prime存放着小于N的素数   
int isNotPrime[N] = {1, 1};        // isNotPrime[i]如果i不是素数,则为1 
int Prime()    
{     
     	for(ll  i = 2 ; i < N ; i ++)       
       	{            
		if(! isNotPrime[i])               
	 		prime[num_prime ++]=i;  
	   //无论是否为素数都会下来     
		for(ll  j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)
    		{               
		      	isNotPrime[i * prime[j]] = 1;  
	  		if( !(i % prime[j] ) )  //遇到i最小的素数因子
	  			//关键处1                  
				break;           
		}        
	}        
	return 0;   
}  

基本思想

1.

如果 i 都是是素数的话,那简单,一个大的素数 i 乘以不大于 i 的素数,这样筛除的数跟之前的是不会重复的。筛出的数都是 N=p1*p2的形式, p1,p2之间不相等

2.
当前数字i是合数,则i=p1^a * p2^b * p3^c(p1小于等于p1的素数乘以i得到的数。比如p1之前有pi,pj和pk三个素数,则此次循环筛掉pi*i,pj*i,pk*ip1*i,实现见代码的关键一prime 里的素数都是升序排列的,break时的遇到能整除的第一个prime[j] 就是这里的p1

结论:

1.一个数肯定不会被重复筛除

2.合数肯定被重复筛除。

关键:按照一个数的最小素因子筛选

图解:

参考:https://www.jianshu.com/p/f16d318efe9b
线性筛素数 证明详解_第1张图片
从图上我们看到,第一列筛掉的是最小素因子是2的数,第二列筛掉的是最小素因子为3的数,依次类推,可以把所有的合数都筛掉

因为是按照最小素因子筛选,所以可以保证每个数都只会被筛一遍

 

另一个证明:

参考:https://blog.csdn.net/leolin_/article/details/6642126

原理:
1. 任何一个合数都可以表示成一个质数和一个数的乘积
2. 假设A是一个合数,且A = x * y,这里x也是一个合数,那么有:
       A = x * y; (假设y是质数,x合数)
       x = a * b; (假设a是质数,且a < x——>>a)
 ->  A = a * b * y a * Z (Z = b * y)
即一个合数(x)与一个质数(y)的乘积可以表示成一个更大的合数(Z)与一个更小的质数(a)的乘积!!!!
这也是理解代码中 if(i%primes[j] == 0)break;的关键
例如: 如果i = 8; 那么由于i%2 == 0; 因此对于i=8就只需要检查primes[1]=2即可,因为对于大于primes[1]的质数,像3,有:
        8*3 = 2*4*3 = 12*2
也就是说24(8*3=24)并不需要在8时检查,在12时才检查

你可能感兴趣的:(模板,数学----数论,2018暑假ACM集训)