资料来源:https://blog.csdn.net/danliwoo/article/details/51871740
线性筛用在素数、欧拉函数、莫比乌斯函数的打表上。
埃拉托斯特尼筛法
一开始最容易理解的筛法是酱紫滴~
#define N 1000100
#define LL long long
int num[N], prim[N];
int pn = 0;
void table(){
memset(num, -1, sizeof(num));
for(int i = 2;i < N;i++) if(num[i]){
prim[pn++] = i;
for(LL j = 1LL*i*i;j < N;j += i) if(num[j])
num[j] = 0;
}
}
注意在标记i
的倍数只需从i*i
开始,因为小于它的i
的倍数势必已经被更小的数作为倍数筛掉。同时小心i*i
爆int
。但是这个写法会让一些数被重复筛。如30,会被2、3、5作为倍数筛三遍,这样的访问太多余了。
欧拉筛法
这个筛法做到了每个数只被筛一遍。
#define N 100100000
#define LL long long
int num[N], prim[N];
int pn = 0;
void table(){
memset(num, -1, sizeof(num));
for(int i = 2;i < N;i++){
if(num[i]) prim[pn++] = i;
for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){
num[i*prim[j]] = 0;
if(i % prim[j] == 0) break;
}
}
}
全篇的精华在于:
if(i % prim[j] == 0) break;
附赠打表
充分利用了欧拉函数、莫比乌斯函数作为积性函数的性质,灰常好写~
#define N 100100
#define LL long long
int num[N], prim[N], phi[N] = {1,1}, mob[N]={1,1};
int pn = 0;
void table(){
memset(num, -1, sizeof(num));
for(int i = 2;i < N;i++){
if(num[i]) {
prim[pn++] = i;
phi[i] = i-1;
mob[i] = -1;
}
for(int j = 0;j < pn && 1LL*i*prim[j] < N;j++){
if(i % prim[j] == 0){
phi[i*prim[j]] = phi[i] * prim[j];
num[i*prim[j]] = 0;
mob[i*prim[j]] = 0;
break;
}
phi[i*prim[j]] = phi[i] * (prim[j]-1);
num[i*prim[j]] = 0;
mob[i*prim[j]] = -mob[i];
}
}
}