欧拉筛(线性筛)
在素数筛法当中,首先先讲一下朴素的筛法和埃氏筛。
朴素筛法:对于任何一个数
埃氏筛:我们发现,在朴素筛法当中我们希望枚举每个数的因子,也就是说,当我们判断4是不是素数,我们枚举了2,判断6是不是素数,又枚举了2,那我们可不可以在判断2是不是素数的时候,发现2是素数,就直接把它的倍数都筛掉。这就是埃氏筛。
#include<bits/stdc++.h>
using namespace std;
int n,tot;
int Prime[100010];
bool vis[1000010];
int main() {
cin >> n;
for(int i = 2;i <= n;i++) {
if(!vis[i]) {
Prime[++tot] = i;
for(int j = 2;j * i <= n;j++)
vis[j * i] = true;
}
}
for(int i = 1;i <= tot;i++)
cout << Prime[i] << " ";
return 0;
}
欧拉筛:尽管埃氏筛貌似已经非常优秀了,但是我们仍然发现它也并不是那么令人满意,因为,以18这个数为例,我们在枚举到6的时候用6和素数3把18筛掉,枚举到9的时候又用9和素数2把18筛掉。这样就造成了冗余的操作从而浪费了时间。保证一个数一定只被筛掉一遍,这就是欧拉筛的核心思想,一个数如果不是素数,那么一定只被它的最小的素数因子筛掉。同样地以18为例,
#include<bits/stdc++.h>
using namespace std;
int n,tot;
int Prime[100010];
bool vis[1000010];
int main() {
cin >> n;
for(int i = 2;i <= n;i++) {
if(!vis[i]) Prime[++tot] = i;
for(int j = 1;j <= tot && i * Prime[j] <= n;j++) {
vis[i * Prime[j]] = true;
if(i % Prime[j] == 0) break;
}
}
for(int i = 1;i <= tot;i++)
cout << Prime[i] << " ";
return 0;
}