埃氏筛法:
整数的唯一分解定理:
任何一个大于1的自然数 N,如果N不为质数,都可以唯一分解成有限个质数的乘积N=P1 ^ a1 · P2 ^ a2 · P3 ^ a3 · … · Pn ^ an ,这里P1<P2<P3<…<Pn均为质数,其诸指数 ai 是正整数。
bool vis[maxN];
void init()
{
memset(vis,false, sizeof(vis));//所有数初始化为0->质数
vis[0]=true;
vis[1]=true;
}
void Is_Prime()
{
init();
for(int i=2;i<=N;i++)
{
if(!vis[i])
for(int j=i*i;j<=N;j+=i)
vis[j]=true;
}
}
C++ 语言默认就有 bool 及 true 和 false。C 语言默认只有 _Bool 及 0 和 1 值,在 include 标准库 <stdbool.h> 后才变成 bool 及 true 和 false。
埃氏筛法无法避免重复地筛一些数,比如说30=2 * 15=3 * 10=5 * 6,所以为了避免重复筛数,我们有线性筛!
线性筛(欧拉筛法)
线性筛是在埃氏筛法的基础上,让每一个合数,只被它的最小质因子筛选一次,达到不重复的目的。
怎么理解呢?根据最开始所说的整数的唯一分解定理,每个合数有且只有一组质数相乘可以得到,前面的埃氏筛法,每一个质因子都要筛掉该合数一次,我们如果让每个合数只被它最小的质因子筛选就完全避免了埃氏筛法的重复。从算法来说,N范围内的每个数都只会被筛一次,所以算法复杂度是O(n)。
bool vis[maxN];
int prime[maxN],cnt;
void init()
{
memset(vis,false, sizeof(vis));//所有数初始化为0->质数
vis[0]=true;
vis[1]=true;
cnt=0;
}
void Is_Prime()
{
init();
for(int i=2;i<=N;i++)
{
if(!vis[i])//i是质数
prime[++cnt]=i;//prime是用来存质数的数组,显然数组中的质数是从小到大
for(int j=1;j<=cnt;j++)
{
if(i*prime[j]>N)//超出了范围
break;
vis[i*prime[j]]=true;
if(i % prime[j] == 0)//跑到了i的最小的质因数
break;
}
}
}