线性筛选素数。。。。线性哦

上一篇一道题目用到了筛选素数,不过是那个只需要求3400以内的,比较少,无所谓,关键是如果要求1000000以内的,再直接求就不行了,太慢了。

下面给出两个自己用的模版,并解释解释,为何这样能够很快计算出素数。

代码1,这个有点长,但是很好理解

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int prime[100000];
bool s[1000010];


void Prime()//求素数
{
    int i,j,k,t;
    
    for (i=2;i<=1000000;i+=2) s[i]=0;
    for (i=1;i<=1000000;i+=2) s[i]=1;
    s[1]=0; s[2]=1;
    for (i=3;i<=1010;i+=2)//如果要求10000以内的素数,你至少要看i%sqrt(10000)都不可约才行,这也是为什么1000000以内只要i<=1000就行了的道理
    {
        if (s[i])
        {
            k=2*i;//应为所有偶数已经剔除,所以此处t=3*i(相当于)也就是此次剔除的仍是奇数,所以避免了重复剔除偶数,速度快。
            t=i+k;
            while (t<=1000000)
            {
                s[t]=0;
                t=t+k;
            }
        }
    }
    k=1; prime[1]=2;
    for (i=3;i<=1000000;i+=2)
    {
        if (s[i]==1) { k++; prime[k]=i; }
    }
    prime[0]=k; 
}


上面这个实际上就是先踢出了所有偶数,然后呢,以后要踢出的只能是奇数,否则你就重复预算了。k=2*i 是个偶数,i是奇数,3*i也是奇数,那么每次t=i + k都是奇数。所以每次去除的都是奇数倍了。

 

这样处理后基本上每个数只判断一次就知道是不是素数了,所以是线性。。。

 

代码2:难理解一点

const int M = 3000500;
int p[400010], pNum;
bool f[M];
void Prime()
{
	int i, j;
	for(i = 2; i < M; i++) {
		if(!f[i]) { p[pNum++] = i; }
		for(j = 0; j < pNum && p[j] * i < M; j++ ) {
			f[p[j]*i] = 1;
			if(!(i%p[j]))
				break;
		}
	}
}


这个其实和上面那个是同一个道理。首先f[i]==0就是素数,从2开始。然后我们要去除已经取得素数的i倍的数,f[p[j]*i] = 1;

关键就是下面那句话不好理解,因为正是那句跳出循环才能保证筛选素数是线性的。

为什么i能除尽p[j]这个素数就跳出呢?

其实可以简单证明一下:

合数可以由一个质数数与另一个数相乘得到
而同时假设合数a=质数b×质数c×一个数d
令e=c × d,假设b ≥ c,e为合数,令f=d × b
a=f × c ,其中c
即大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
这也是if(!( i % prime[j]))break;的含义,这也是线性筛法算质数表的关键所在

 

举个例子:

比如i = 9,现在素数是2 3 5 7

进入第二重循环了,f[2 * 9] = 1;f[3 * 9] = 1;

这个时候9%3==0,要跳出了,为什么不做f[5* 9] =1;呢?

因为5 * 9 可以用3 * 15来代替,如果这个时候你计算了,那么到i=15的时候这个数还会被重复计算一次,所以这里大量避免了重复运算,所以也就节省了时间。

 

这里总结一句话就是,一个大的合数和这个能除尽的质数的乘积,一定能被一个比起小的质数和合数更大的合数乘积来代替。

不懂的时候想想 5*9 = 5*3*3 = 3*15就是这个道理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值