分别是线性筛素数,欧拉函数,莫比乌斯函数,约数个数,约数和,其中有些都是可以一起筛的
这里给出分别的模板
1. 素数
最基本的,后面基本都要用到素数的筛法
const int N=1e7+50;
int p[N];
//true表示被筛,即不是素数
bool check[N];
int n,m,a;
void init(){
int t;
check[1]=true;
for(int i=2;i<=n;i++){
//素数,直接记录
if(!check[i]){
p[++p[0]]=i;
}
//p[0]记录的是素数个数
//枚举现在已知的所有素数
for(int j=1;j<=p[0];j++){
//筛掉p[j]的倍数
t=i*p[j];
if(t>n){
break;
}
check[t]=true;
//保证i*p[j]这个数只被访问一次
//要不是为i的倍数时访问,要不是为p[j]的倍数时访问
if(i%p[j]==0){
break;
}
}
}
}
2. 欧拉函数
const int N=1e7+50;
int p[N],phi[N];
bool check[N];
//同时筛出素数和欧拉函数
void init(){
int t;
check[1]=true;
phi[1]=1;
for(int i=2;i<=N;i++){
if(!check[i]){
p[++p[0]]=i;
phi[i]=i-1;
}
for(int j=1;j<=p[0];j++){
t=i*p[j];
if(t>N){
break;
}
check[t]=true;
//t拥有多个相同质因子(p[j]至少就2次)
if(i%p[j]==0){
//i是p[j]的倍数,那t和i的质因子相同,由欧拉函数计算式可得两者只差一个系数
phi[t]=phi[i]*p[j];
}else{
//欧拉函数是积性函数
phi[t]=phi[i]*(p[j]-1);
}
}
}
}
3. 莫比乌斯函数
const int N=1e7+50;
//同时筛出素数和莫比乌斯函数
int p[N],miu[N];
bool check[N];
int pre[N];
void init(){
int t;
miu[1]=1;
check[1]=true;
for(int i=2;i<=N;i++){
if(!check[i]){
p[++p[0]]=i;
miu[i]=-1;
}
for(int j=1;j<=p[0];j++){
t=i*p[j];
if(t>N){
break;
}
check[t]=true;
//有平方因子,函数值为0
if(i%p[j]==0){
miu[t]=0;
}else{
//质因子数量改变,符号改变
miu[t]=-miu[i];
}
}
}
}
4. 约数个数
const int N=1e7+50;
//num记录最小质因子指数
int d[N],num[N],p[N];
bool check[N];
void init(){
int t;
d[1]=1;
check[1]=true;
for(int i=2;i<=N;i++){
if(!check[i]){
d[i]=2;
num[i]=1;
p[++p[0]]=i;
}
for(int j=1;j<=p[0];j++){
t=i*p[j];
if(t>N){
break;
}
check[t]=true;
//t比i多了一个最小质因子次数
if(i%p[j]==0){
num[t]=num[i]+1;
d[t]=d[i]/(num[i]+1)*(num[i]+2);
}else{
//t比i多了一个不同的质因子,次数为1,根据公式得出两倍关系
num[t]=1;
d[t]=d[i]*2;
}
}
}
}
5. 约数和
σ ( x ) = ( 1 + p 1 1 + p 1 2 + … + p 1 a 1 ) ( 1 + p 2 1 + p 2 2 + … + p 2 a 2 ) … ( 1 + p 1 + p n 2 + … + p n a n ) σ(x)=(1+p_1^1+p_1^2+…+p_1^{a1})(1+p_2^1+p_2^2+…+p_2^{a2})…(1+p^1+p_n^2+…+p_n^{an}) σ(x)=(1+p11+p12+…+p1a1)(1+p21+p22+…+p2a2)…(1+p1+pn2+…+pnan)
const int N=1e7+50;
//prod记录一个以1为首项,i的最小质因子为公比的等比数列和
int prod[N],sumd[N],p[N];
bool check[N];
void init(){
int t;
prod[1]=sumd[1]=1;
check[1]=true;
for(int i=2;i<=N;i++){
//素数因子只有1和本身
if(!check[i]){
prod[i]=sumd[i]=i+1;
p[++p[0]]=i;
}
for(int j=1;j<=p[0];j++){
t=i*p[j];
if(t>N){
break;
}
check[t]=true;
if(i%p[j]==0){
//t中p[j]的次数比i中的多一次,更新prod
prod[t]=prod[i]*p[j]+1;
//类似约数个数的一个更新
sumd[t]=sumd[i]/prod[i]*prod[t];
}else{
//p[j]为t的最小质因子,由公式可得
prod[t]=p[j]+1;
sumd[t]=sumd[i]*(p[j]+1);
}
}
}
}