埃氏筛法
基本思想 :从2开始,将每个质数的倍数都标记成合数,剩下的没有被标记的就是素数,从而达到筛选素数的目的.
代码实现:
int vis[maxn]={0};
void prime(){
vis[0] = vis[1] = 1; //0 和 1不是素数
for (int i = 2; i <= maxn; i++)
{
if (!vis[i])
{ //如果i是素数,让i的所有倍数都不是素数
for (int j = i*i; j <= maxn; j += i)
{
vis[j] = 1;
}
}
}
vis[i]数组是标记素数,如果i是素数,则vis[i]=0,否则vis[i]=1;
欧拉筛法
在埃氏筛法中,有些数会被标记多次,例如30=2 * 15=3 * 10=5 * 6被标记了3次
因此为了解决重复标记问题,出现了欧拉筛法,它是根据每个合数只有一个最小质因子,因此欧拉筛法中每个合数 m 只能根据 m 最小的质因子的倍数所标记
代码实现:
int p[maxn]={0};
int vis[maxn]={0};
void prime()
{
int t=0;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
{
t++;
p[t]=i;
}
for(int j=1;j<=t&&i*p[j]<=maxn;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0)
break;
}
}
}
p[i]数组记录的是各个素数,t是素数的个数(t是随着程序的进行而增加的),很显然欧拉筛法中p[j]是最小的质因子,每个合数是根据它的倍数即I*p[j]所标记;
重点解释if(i%p[j]==0) break;是因为当i是p[j]的倍数的时候,i=k * p[j],如果循环继续下去,则需标记i * p[j+1],而i * p[j+1]=p[j] * k *p[j+1]其中p[j]是最小素数,但i * p[j+1]是用p[j+1]的倍数所标记的,当j=k * p[j+1],则会重复标记此书
例如:i=8;j=1;p[j]=2; i/p[j]=4; p[j+1]=3; 3 * 8=3 * 2 4=2 * 12;
当i=12时,j=1时,i p[j]=24被标记,而不是用8 * p[2]=24标记