线性筛法

  • 看了好多线性筛,把代码整理一下。看之前请先看我在文章中的链接,我写这篇文章的目的主要是我在学习中,对有些不懂地方的注释,以及我的理解。
  • 参考链接
    各种线性筛法的前提是知道线性筛素数的原理,具体的原理我贴下这位大佬的博客线性筛素数的原理
    我是按照每个数都是被他最小的质因子筛去的。
    然后是线形筛欧拉函数、约数个数、约数和、乌比莫斯函数。具体讲解传送门
线性筛素数
  • 代码和解释
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) 
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值