前言
线性筛是筛素数一种比较常用的方法(实际上,它的用途含有很多,如筛(mu,phi)等玄学的函数)。它的时间复杂度近似于(O(n))。
代码(代码后面有解析)
#include<bits/stdc++.h>
using namespace std;
int n;
map<int,int> Is_Prime;//保存每一个数是否为质数
vector<int> Prime;//保存全部质数
int main()
{
scanf("%d",&n);//筛选2~n内的质数
for(int i=2;i<=n;i++) Is_Prime[i]=1;//先默认全部都是质数
for(int i=2;i<=n;i++)
{
if(Is_Prime[i]) Prime.push_back(i);//如果这个数是质数,就将其保存下来
for(int j=0;j<Prime.size();j++)//将这个数与已有的质数进行操作
{
Is_Prime[i*Prime[j]]=0;//将这个数与该质数的积标记为非质数
if(!(i%Prime[j])) break;//如果当前数是该质数的倍数,就退出循环(这个在后面会进行解释)
}
}
printf("%d
",Prime.size());
for(int i=0;i<Prime.size();i++) printf("%d ",Prime[i]);
return 0;
}
解释
对于(2sim n)之间的一个整数(i),有两种可能性:
一:它是质数。则此时(Prime[j])必为(i)(一个质数只能被(1)和本身整除,而(Prime[j])不可能为(1),故(Prime[j])为(i)),而(i)是刚保存下来的,必然在最末尾,即i后面没有其他可操作的数了,于是退出循环
二:它是合数。则可得(i=Prime[j]*x)((x)为(2sim i)之间的一个整数),此时又有两种可能性:
1:(x)是质数。则(xge Prime[j])(若(x<Prime[j]),则在对(Prime[j])进行操作前就会对(x)进行操作并退出循环),那么(i)与(Prime[j])之后的任意一个数(t)的积(i*t)都可以表示为(Prime[j]*x*t),而(x*t)是一个合数,所以在轮到对(x*t)和(Prime[j])进行操作时时就可以得到(i*t),故不需要继续操作了,可以退出循环
2:(x)是合数。则(x)可以分解为(a*b)的形式(其中(a)是所能取值的数中的最小质数),那么(i=a*b*Prime[j])。对于(a)和(Prime[j])的大小关系,又有两种可能性:
①:(a<Prime[j])。显然不可能(否则在对(Prime[j])进行操作前就会对a进行操作并退出循环)
②:(age Prime[j])。(∵age Prime[j],∴b*Prime[j]le x),那么(i)应在对(x)进行操作就已经在对(b*Prime[j])进行操作的时候的时候被判定为非质数,自然无需再判一遍。