筛素数

所谓素数,就是因数只有1和自身的数(废话),但我们不讨论1(废话*2)

如果一个数n是合数,那么每一个{d| d|n,d<=√n}都会有一个大于√n的的数c使c*d=n

 

因此,暴力筛的话只要枚举到√n即可,不过判断一个数就是O(√n),那么筛多了复杂度就无法想象,这种方法多用于判断而不是筛

  那么我们就不要暴力了。

   筛法1:埃氏筛   复杂度O(nloglogn)

    原理:若一个数是质数,那它的倍数都是合数。(显而易见的东西不需要证明)

   代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,pri[100001];
bool bj[10000001];
void  getpri()
{  int k=0;
   for(int i=2;i<=n;i++)
   {if(!bj[i]){pri[++k]=i;
      for(int j=2;i*j<=n;j++)
      bj[i*j]=1;
    }
   }
}
int main()
{
    scanf("%d",&n);
    getpri();
    for(int i=1;pri[i]<=n;i++)
    {if(pri[i])
      printf("%d ",pri[i]);
      else break;
    }
    return 0;
}

当然这还是太慢了(只能筛到1e6,大了就爆了)

对于大数据,我们还是希望它的复杂度逼近线性

so,就有了线性筛

 线性筛是什么呢?

   我们从埃氏筛讲起。埃氏筛会将一个合数重复标记,造成时间的浪费,而线性筛就是避免重复标记的一种筛法。

   埃氏筛中j*i枚举的是质数i的倍数,但当j1%i==0时,i*j1一定可以被j/i所标记。那么当j>j1的时候,就可以让另一个数来标记,从而跳出内循环,这样就不会造成重复标记,相当于对于每个合数n,都会被n的最小质因子标记

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,pri[100001];
bool bj[10000001];
void  getpri()
{  int k=0;
   for(int i=2;i<=n;i++)
   {if(!bj[i]){pri[++k]=i;
      for(int j=1;j<=k;j++)
      {bj[i*pri[j]]=1;
        if(i%pri[j]==0)//这里枚举i的质数倍,如果i中已经有质因子了,那么pri[j]*i一定可以被另一个数标记
        {break;
        }
      }
   }
}
int main()
{
    scanf("%d",&n);
    getpri();
    for(int i=1;pri[i]<=n;i++)
    {if(pri[i])
      printf("%d ",pri[i]);
      else break;
    }
    return 0;
}

 

posted @ 2019-04-09 21:03  千载煜  阅读(136)  评论(0编辑  收藏  举报