关于筛法

Posted wengsy150943

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于筛法相关的知识,希望对你有一定的参考价值。

众所周知,筛法是打素数表的重要方法。基础的筛法也是很容易的,不需要多加赘述。这里提供一个优化的方法。

一般使用的筛法都是埃拉托斯特尼筛法,其代码如下:


void getPrime()  {      

 prime[0]=false;    

 prime[1]=false;     

 for (int i=2;  i<INT_MAX;  i++)        

   if (prime[i]) {         

  primes[++cnt ]=i;    

  for (int k=i*2; k<INT_MAX; k+=i)       

   prime[k]=false;      

   }      

}   

这种筛法简单易懂,但缺点是经常会多筛去合数,最简单的例子就是6,会被2,3分别筛去。当表的规模很大时,这个额外开销是惊人的。

有一些常数级的优化会被应用以减少这种开销,比如特判2后+2进行。改良后的代码如下:

void getPrime()  {      

 prime[0]=false;    

 prime[1]=false;

 prime[2]=true; 

 tot=0;      

 for (int i=3;  i<INT_MAX;  i+=2)  //这里间距改为了2      

   if (prime[i]) {         

  primes[++tot ]=i;    

  for (int k=i*3; k<INT_MAX; k+=2*i)       //这里的优化似乎比较少人做?事实上i的偶数倍显然是应该被剔除的

   prime[k]=false;      

   }      

}   

但这种优化并不能一劳永逸地解决问题。于是我又查到一个更有效的筛法,代码如下:

void getPrime(){
 prime[0]=1;

 prime[1]=1;

 tot=0;
 for(int i=2;i<MAX;i++){
  if(!prime[i])
   primes[tot]=i,tot++;
  for(int j=0;j<tot&&i*primes[j]<MAX;j++){
   prime[i*primes[j]]=1;
   if(i%primes[j]==0) break;
  }
 }
}

有人把它称作欧拉筛法,也有人称为快速线性筛法。它从根本上杜绝了重复筛合数的问题,保证每个合数只会被它最小的质因子筛去。一般情况下这样的效率已经足够了,但我们会发现,对普通筛法的优化在这里还适用。于是继续优化:

 

void getPrime(){
 prime[0]=1;

 

 prime[1]=1;

 

 tot=0;
 primes[tot]=2;
 tot++;
 for(int i=3;i<MAX;i+=2{
  if(!prime[i])
   primes[tot]=i,tot++;
  for(int j=0;j<tot&&i*primes[j]<MAX;j++){
   prime[i*primes[j]]=1;
   if(i%primes[j]==0) break;
  }
 }
}

 

 这样折腾一个简单算法的优化也没谁了......
























以上是关于关于筛法的主要内容,如果未能解决你的问题,请参考以下文章

「关于张博航提到的筛法的理解」——一种处理关于$p$成多项式的数论函数筛法

线性筛法

素数专题——素数筛法

积性函数求和:筛法DP洲阁筛

51nod 1184 第n个素数

关于欧拉函数与莫比乌斯函数等一系列积性函数的线性筛