介绍两种筛法

第一种:埃拉托斯特尼(Eratosthenes)筛法
简称:普通筛或埃氏筛

时间复杂度:O(nloglogn)

下面上普通筛法的两种写法及优化

写法1:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5;
int a[N];
void ss(int n){
	memset(a,-1,sizeof(a));//a[i]=-1 先假定所有数都为素数,i是素数a[i]=-1,不是素数a[i]=0 
	a[0]=a[1]=0;
	for(int i=2;i<=n;i++)
		if(a[i])
		for(int j=i*2;j<=n;j+=i) a[j]=0; //从i*2,开始以他自身为倍数相加的数都是合数 
}
int main(){
	int n;
	while(cin>>n){
		ss(n); 
		for(int i=2;i<=n;i++)
			if(a[i]) cout<<i<<endl;
	}
} 

写法2:最后一个for循环可以改写一下
实质一样。

void ss(int n){
	memset(a,-1,sizeof(a));
	a[0]=a[1]=0;
	for(int i=2;i<=n;i++)
		if(a[i])
		for(int j=2;j*i<=n;j++) a[i*j]=0; 
}

两处优化,上代码。

void ss(int n){
	memset(a,-1,sizeof(a));
	a[0]=a[1]=0;
	for(int i=2;i<=sqrt(n);i++)//优化1:只需要到sqrt(n) 
		if(a[i])
		for(int j=i*i;j<=n;j+=i) a[j]=0; //j从i*i开始 
}

第二种:欧拉筛法。

时间复杂度:O(n)
原理与普通筛类似,只是避免了重复筛同一个合数
下面上代码

const int N=1e5;
bool a[N];
void Ess(int n){
	 memset(a,true,sizeof(a));
	 int p[N],cnt=0;
	 for(int i=2;i<=n;i++)
	 {
	 	if(a[i]) p[cnt++]=i;
	 	for(int j=0;j<cnt&&i*p[j]<=n;j++)//每个合数只用其最小质因数去筛 
	 	{
	 		a[i*p[j]]=false;
	 		if(i%p[j]==0) break; 
		}//如果i能被p[j]整除,说明i*p[j+1]已经被筛过,因为i是p[j]的倍数,所以i*[p+1]是p[j]的倍数 
	 } 
} 

注意以上两种筛法1都要特判,
如果题目给的范围还有需要将1特判

----定理-----:任意大于1的整数的最小因数是素数。
而且对合数进行筛选时,它的所有因数一定都被筛过了。

看完以上两种素数筛法:去洛谷练练手,
题目传送门:模板题