【学习笔记】欧拉线性筛
欧拉线性筛
简介
欧拉线性筛主要用于求\(n\)以内的所有素数,时间复杂度为\(O(n)\)
算法实现
欧拉线性筛的原理是保证\(n\)以内的所有素数只被他所含有的最小质因子筛过,这样就使得每个素数只被筛过了一次。
我们设一个数组\(prime[i]\)表示第\(i\)个素数是多少,\(is\_prime[i]\)表示第\(i\)个数是否为素数。
对于外层循环,我们枚举从1枚举到\(n\),如果当前\(i\)为素数,那么我们就把它加入到\(prime[]\)数组中。
对于当前已经出现过的素数\(prime[j]\),那么它与\(i\)的乘积就一定为合数,所以\(is\_prime[prime[j]*i]=1\)。注意在枚举\(j\)时,\(j\le tot,i*prime[j]\le n\)
欧拉函数的精华
\[if(!i\%prime[j])\ break;
\]
这条语句保证了所有数只被它最小的质因子筛到。
对于当前所有\(prime[j]\)筛到的数,都含有一个因数\(i\),上面这条语句一旦执行,就表示\(prime[j]\)就是\(i\)最小的质因子,我们令\(a=prime[j]\),则往后所有的\(prime[j]>a\),所以往后筛到的所有数的最小质因子都是\(a\),不用\(prime[j]\)来筛掉,所以终止循环。
模板代码
#include<bits/stdc++.h>
#define maxn 100000010
using namespace std;
int n,q,tot=0,prime[maxn];
bool isprime[maxn];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>q;
memset(isprime,1,sizeof(isprime));
for(int i=2;i<=n;i++){
if(isprime[i])prime[++tot]=i;
for(int j=1;prime[j]*i<=n&&j<=tot;j++){
isprime[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
while(q--){
int k;
cin>>k;
cout<<prime[k]<<endl;
}
return 0;
}