素数筛法
= =素数是一个很重要的块,所以筛法也是灰常重要的
首先 是传统筛法
第一版:
1 #define MAXN 1000001 2 bool isprime[MAXN]; 3 long prime[MAXN]; 4 int cnt; 5 void getprime() 6 { 7 int i,j; 8 memset(isprime,1,sizeof(isprime)); 9 isprime[0]=isprime[1]=cnt=0; 10 for(i=2;i*i<MAXN;i++) 11 { 12 if(isprime[i]) 13 { 14 for(j=i*i;j<MAXN;j+=i) 15 { 16 if(isprime[j]) 17 { 18 isprime[j]=false; 19 } 20 } 21 22 } 23 } 24 for(i=2;i<MAXN;i++) 25 { 26 if(isprime[i]) 27 prime[cnt++]=i; 28 } 29 }
ps:其实我个人感觉这个算法平常的一些题是够用的( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)(快学习!
第二版:
#define MAXN 1000001 bool isprime[MAXN]; long prime[MAXN]; int cnt; void getprime() { int i,j; memset(isprime,true,sizeof(isprime)); isprime[0]=isprime[1]=cnt=0; for(i=3;i<MAXN;i++) prime[i]=i%2==0?0:1; for(i=2;i<t;i++) { if(isprime[i]) { for(j=i*i;j<MAXN;j+=i) { if(isprime[j]) { isprime[j]=false; } } } } for(i=2;i<MAXN;i++) { if(isprime[i]) prime[cnt++]=i; } }
相比于第一版,先去除了2以后的偶数,因为这些偶数根本不可能是素数嘛(~ ̄▽ ̄)~,( ̄ε(# ̄)☆╰(废话
嗯,容我测试一下时间= =,额……这时间不稳定!(╯‵□′)╯︵┻━┻ 怎么时间还增加了啊喂
仔细想了想 我们可以把第一版储存素数的数组放入循环,但第二版是不可以的,因为优先判断了偶数和奇数,而且我们可以将i*i<MAXN 判断化为 temp=sqrt(MAXN)+1 ;i<temp 从而避免每次计算i*i
ps:将储存数组放入循环后,如果你想得到更大的素数需要修改MAXN的值,当然你也可以将储存数组放在外面,下面的算法也均将储存数组放在循环内,但是对于较大值的MAXN,为了效率,我建议使用线性筛法
第三版
1 #define MAXN 1000000 2 3 long cnt,temp=sqrt(MAXN)+1; 4 bool isprime[MAXN]; 5 long long prime[MAXN]; 6 7 void getprime() 8 { 9 int i,j; 10 memset(isprime,1,sizeof(isprime)); 11 isprime[0]=isprime[1]=cnt=0; 12 for(i=2;i<temp;i++) 13 { 14 if(isprime[i]) 15 { 16 prime[cnt++]=i; 17 for(j=i*i;j<MAXN;j+=i) 18 { 19 if(isprime[j]) 20 { 21 isprime[j]=false; 22 } 23 } 24 } 25 } 26 }
嗯,现在我们再来测测时间……,(╯‵□′)╯︵┻━┻,到底怎么测啊不会啊喂!老是不稳定!( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)(学习!
----------------------------------------------------------------------------------------------------------------------------------------
下面我们试试线性筛法
#define MAXN 1000000 long cnt;bool isprime[MAXN]; long long prime[MAXN]; void x_getprime() { int i,j; memset(isprime,1,sizeof(isprime)); isprime[0]=isprime[1]=cnt=0; for(i=2;i<MAXN;i++)//下面循环考虑了超出的情况,所以可以直接使用MAXN { if(isprime[i]) prime[cnt++]=i;//与上面一样将储存素数步骤放入循环 for(j=0;j<cnt&&i*prime[j]<MAXN;j++)//因为这里for循环判断上下均使用i*prime[j]所以我们不将i*prime[j]储存起来,while可以储存试试 { isprime[i*prime[j]]=false; if(!(i%prime[j]))break;//关键点 } } }
传统的筛法和线性素数筛法的区别是,线性筛法不会筛掉同一个数多次,原因在关键点上下面我们来研究一下线性筛法
首先,筛掉合数:
首先对于一个数num 其能写成 p1*p2(素数*素数)形式 则其肯定第一次被筛掉
若其能 n*p(合数*素数)形式,则其也能写成(p1*p2*……pn)的素数形式,则也筛掉
其次,不重复:
从上面的循环我们可以看出i一定大于等于prime[j],当i=prime[j] 时我们就退出循环
而传统筛法里,6=2*3=3*2是被重复筛掉的,而线性筛法中对于6 我们只进行6=2*3的删除
嗯,以上是今天的的筛法的学习。
参考:http://blog.csdn.net/dinosoft/article/details/5829550
该网页最后也有一种针对奇数的筛法,但我笔记本快没电了( ̄ε(# ̄)☆╰╮(谁叫你不带电源
所以回去了再看……嗯现在可以去试试TLE的几道题……