小言_互联网的博客

质数筛以及质因数分解

294人阅读  评论(0)

今天正式学了一遍质数筛(已经可以打线性的质数筛了!)以及质因数分解,要做一个小小的总结。

知识点前缀:

  1. 质数:除了1和它本身没有其他的因数,一般指的都是正整数。;
  2. 筛法:筛法是一种简单检定素数的算法。
  3. 筛法的来源:因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛法”,简称“筛法”。
  4. 筛法的具体做法:给出要筛数值的范围n,找出n以内的素数p1,p2,p3,…,pk。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个素数5筛,把5留下,把5的倍数剔除掉;不断重复下去…。
  5. 唯一分解定理:任何一个大于1的正整数都能够被唯一分解为有限个质数的乘积。

质数筛

对于质数筛而言,我们有三种做法:

1.试除法 O ( n ) O(\sqrt{n})

根据定义出发:若是我们除了1和它本身找到了其他的因子,那么这个数字一定不是质数,反之,则为质数。

那么,对于0和1本身,我们既要进行特殊判断,他们既不是质数也不是合数。

枚举因数的时候我们只需要枚举到根号即可,因为这样就可以判断他的所有的因数。(自行思考……)

bool primes(int x)
{
	if(x<2)	return false;
	for(int i=2;i<=sqrt(n);++i)
		if(n%i==0)	return false;
	return true;
}

2.Eratosthenes 筛法 O ( n l o g l o g n ) O(nloglogn)

上面的方法是我们直接判断该数字是不是质数,这样的话,我们每次只可以判断一个数字,效率极低。

那,我们想一下,是否可以直接找出一个范围里的质数呢??

如果找质数不好找的话,我们可以通过找合数啊,正难则反,若是合数都被找出来了,那么最后剩下来的不就都是质数了吗?

那么,我们就可以通过已知的质数(2,3,5……)去标记合数。

从2开始,由小到大扫描每一个数字x,把他的倍数2x,3x,4x……都标记为合数。若扫描到一个数字未被标记,则他便不能被(2,x-1)的数字整除,所以该数字就是质数。

我们可以再继续想一下:对于6而言,他会被2,3标记两次(效率极低)……,实际上,小于 x 2 x^2 的x的倍数在扫描更小的数字的时候就已经被标记过了。所以,我们对于数字x而言,我们从x^2开始标记就可以了。

void primes(int x)
{
	memset(v,0,sizeof(v));//合数标记
	for(int i=2;i<=n;++i)
	{
		if(v[i])	continue;
		prime.push_back(i);//该数字是质数
		for(int j=i;j<=n/i;++j)	
			v[i*j]=true; 
	} 
}

3.线性筛选 O ( n ) O(n)

虽然在上面的算法中有小小的优化,但是同样还是不可以改变数字会被该算法同时好多次标记的本质,比如12,36,60,120……这些数字同样会被2,3……同时进行标记……

所以,我们考虑被进一步的优化。

考虑数字x的因数的唯一确定方法:我们可以采用x的最小的质因数的乘积。比如: 12 = 2 2 3 6 = 2 3 12=2*2*3, 6=2*3 ……这样子的话,我们就唯一确定了x的被遍历的方法,所以该数字就只会被遍历一次。

线性筛法的原理:每个合数必有一个最小的质因数的排列方式,用这排列方式把这个合数筛掉。

在每一把该数字的最小的质因子筛完之后,再次遍历到该数字的因数,便可以保证这个因数一定是质因数。(自行思考,还是比较好想的。)

void primes(int x)
{
	memset(v,0,sizeof(v));
	int m=0;//质数的数量 
	for(int i=2;i<=x;++i)
	{
		if(!v[i])	v[i]=i, prime[++m]=i;/*存储质数*/
		for(int j=1;j<=m;++j)
		{
			if(prime[j]>v[i]||i*prime[j]>x)	break;
			v[i*prime[j]]=v[i];	
		}
	} 
}

质因数分解

我们用上面的试除法以及Eratosthenes 筛法,找到 [2, x \sqrt{x} ]中x的所有的因子,并且把该因子在x中全部除尽,使得x中没有了该因子的参与。
比如: 12 = 2 2 3 12=2*2*3 ,那么,对于12而言,我们就需要把两次2都除尽,使得12中只剩下了3的参与。

那么,显然,在上述的过程中可以整除x的数字都是质数。

void primes(int k,int x)
{
	for(int i=2;i<=sqrt(x);++i)
	{
		if(x%i==0)
			while(x%i==0)
				x=x/i, c[i]++;
	}
	if(x!=1)	c[x]++;
}

推荐题目:(注意问题的转化,这些问题有一些拔高,谨慎选做。)
质数距离
阶乘分解
调整公约数

完……


转载:https://blog.csdn.net/qq_43093454/article/details/101637236
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场