- 看了好多线性筛,把代码整理一下。看之前请先看我在文章中的链接,我写这篇文章的目的主要是我在学习中,对有些不懂地方的注释,以及我的理解。
- 参考链接
各种线性筛法的前提是知道线性筛素数的原理,具体的原理我贴下这位大佬的博客线性筛素数的原理
我是按照每个数都是被他最小的质因子筛去的。
然后是线形筛欧拉函数、约数个数、约数和、乌比莫斯函数。具体讲解传送门
线性筛素数
- 代码和解释
const int MAX_N=1e6+7;
int cnt=0,pri[MAX_N];
bool is_p[MAX_N];
void do_prime(){
int i,j,k;
for(i=2;i<MAX_N;i++)
is_p[i]=0;
is_p[1]=1;
for(i=2;i<MAX_N;i++){
if(!is_p[i])
pri[cnt++]=i;
for(j=0;j<cnt&&i*pri[j]<MXN_N;j++){
is_p[i*pri[j]]=1;//把以pri[j]为最小质因子的数筛去
if(i%pri[j]==0)//说明pri[j]是i的最小质因子,i*pri[j+1]这个数的最小质因子是
break; //pri[j],而不是pri[j+1]了
}
}
}
线性求欧拉函数
- 代码和解释
const int MAX_N=1e6+7;
int phi[MAX_N];//pri[i]存放的就是i的欧拉函数值
void do_phi(){
int i,j;
for(i=2;i<MAX_N;i++)
phi[i]=0;
phi[1]=1;
for(i=2;i<MAX_N;i++){
if(!phi[i]){//i是素数
for(j=i;j<MAXN_N;j+=i){//当j==i时,其实就是对素数i求欧拉函数,其他情况是对包含素数i的合数求欧拉函数
if(!phi[j])
phi[j]=j;//初始化
phi[j]=phi[j]/i*(i-1);
}
}
}
return ;
}
线性求莫比乌斯函数
莫比乌斯函数的定义
mo[1]=1
mo[n]=0,如果n包含同一个质因子两个或者两个以上
其他mo[n]=
(
−
1
)
k
(-1)^k
(−1)k,k是n包含不同质因子的种类数
- 代码和解释
const int MAX_N=1e6+7;
int cnt=0,pri[MAX_N];
bool is_p[MAX_N];
void do_mu(){
int i,j,k;
mu[1]=1;
for(i=2;i<MAX_N;i++)
is_p[i]=0;
is_p[1]=1;
for(i=2;i<MAX_N;i++){
if(!is_p[i])
pri[cnt++]=i,mu[i]=-1;//素数i本身的mu[i]=-1,即(-1)^1
for(j=0;j<cnt&&i*pri[j]<MXN_N;j++){
is_p[i*pri[j]]=1;
mu[i*pri[j]]=-mu[i];//i*pri[j]包含的质因子加一,所以取反一下,随着幂的不同-1和1不断变换
if(i%pri[j]==0){
mu[i*pri[j]]=0;//i*pri[j]出现了pri[j]这个质因子两次
break;
}
}
}
}
线性求约数个数
用 d [ i ] d[i] d[i]表示 i i i的约数个数, n u m [ i ] num[i] num[i]表示 i i i的最小质因子出现次数。
- 代码
const int MAX_N=1e6+7;
bool is_p[MAX_N];
int d[MAX_N],num[MAX_N],pri[MAX_N],cnt=0;
void do_d(){
int i,j;
for(i=2;i<MAX_N;i++)
is_p[i]=0;
is_p[i]=1,d[1]=1;
for(i=2;i<MAX_N;i++){
if(!is_p[i]){
pri[cnt++]=i,d[i]=2,num[i]=1;
}
for(j=0;j<cnt&&i*pri[j]<MAX_N;j++){
is_p[i*pri[j]]=1;
if(i%pri[j]==0){
num[i*pri[j]]=num[i]+1;
d[i*pri[j]]=d[i]/num[i*pri[j]]*(num[i*pri[j]]+1);
break;
}
num[i*pri[j]]=1;//pri[j]作为i*pri[j]新的最小质因子,出现次数为1
d[i*pri[j]]=d[i]*2;//累乘
}
}
return ;
}
线性求约数和
f i f_i fi表示 i i i的约数和, g i g_i gi 表示 i i i的最小质因子的 p 0 + p 1 + p 2 + . . . + p k p^0+p^1+p^2+...+p^k p0+p1+p2+...+pk .
- 代码和解释
const int MAX_N=1e6+7;
bool is_p[MAX_N];
int pri[MAX_N],cnt=0;
long long f[MAX_N],g[MAX_N];
void do_f(){
int i,j;
for(i=2;i<MAX_N;i++)
is_p[i]=0;
is_p[1]=1,f[1]=1,g[1]=1;
for(i=2;i<MAX_N;i++){
if(!is_p[i]){
pri[cnt++]=i,f[i]=i+1,g[i]=i+1;
}
for(j=0;j<cnt&&i*pri[j]<MAX_N;j++){
is_p[i*pri[j]]=1;
if(i%pri[j]==0){
g[i*pri[j]]=g[i]*pri[j]+1;//p^0+p^1+p^2+p^3等于(p^0+p^1+p^2)*p+1
f[i*pri[j]]=f[i]/g[i]*g[i*pri[j]];
break;
}
g[i*pri[j]]=pri[j]+1;
f[i*pri[j]]=f[i]*f[pri[j]];//其实也就是等于f[i]*(pri[j]+1)
}
}
}