数论之素数及其相关定理

数论之素数及其相关定理

一、素数定义

基本概念:素数又称质数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。

唯一分解定理:一个数n肯定能被分解成 n=p1^a1 * p2^a2 . . .*pn^an(p是素因子,a是素因子的个数)

​ 因为一个数肯定是由合数和质数构成的,合数又可以分解成质数和合数,最后递归下去就会变成质数的乘积

最后化成了质数相乘的形式

二、素数的判定

朴素算法(时间复杂度O(n)):

bool isprime(int x){
	for(int i=2;i<=x;i++){
		if(x%i==0) return false;
	}
	return true;
}

进阶算法(时间复杂度O(sqrt(n)))

可以注意到如果在2~n-1中,存在n的约数,不妨设为k,即n%k==0,那么由k*(n/k)==n可知,n/k也是n的一个约数,且k与n/k中一定满足其中一个小于等于sqrt(n)、另一个大于等于sqrt(n),其中sqrt(n)为根号n。那么只需要判定n能否2,3…sqrt(n)中的一个整除,即可判定n是否为素数。

bool isprime(int n){
	if(n<=1) return false;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0) return false;
	}
	return true;
}

三、筛法求素数

1、埃氏筛法(时间复杂度O(nloglogn))

素数筛法的关键就在于一个“筛”字。算法从小到大枚举所有数,对每一个素数,筛去它的所有倍数,剩下的即为素数。
数论之素数及其相关定理_第1张图片

const int maxn=1e4+10;
int prime[maxn],pnum=0;//prime数组存放所有素数,pnum为素数个数 
bool p[maxn];//如果i为素数,则p[i]为false,否则p[i]为true 
void find_prime(){
	for(int i=2;i<maxn;i++){
		if(p[i]==false){
			prime[pnum++]=i;
			for(int j=i+i;j<maxn;j+=i){
				//筛去i的倍数 
				p[j]=true;
			}
		}
	}
}

2.欧式筛法(时间复杂度O(n))

欧式筛法对于每个数字,总是被它的最小质因子筛掉,所以每个数字都只遍历一次,所以时间复杂度是O(n)。

首先,我们要保证每一个数字是被他的最小质因子筛掉的,那么我们遍历因子,用已经得到的素因子从小到大的去乘因子。

此时会出现两种情况:1、因子中不包含素因子,那么可以继续乘下去。2、因子中包含了素因子,那么如果因子继续乘下去,所得的积的最小质因子就是之前所包含的素因子,会出现重复筛除,所以break。

int prime[maxn],tot;
bool vis[maxn];
void isprime(){
	for(int i=2;i<maxn;i++){
		if(!vis[i]){
			prime[tot++]=i;
		}
		for(int j=0;j<tot;j++){
			if(i*prime[j]>maxn) break;//判断是否越界 
			vis[i*prime[j]]=1;//筛掉合数 
			if(i%prime[j]==0) break;//判断因子是否包含素因子 
		}
	}
}

四、欧拉函数

1、欧拉函数定义

定义:在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(因此φ(1)=1)。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。欧拉函数是积性函数,当 gcd(a,b)=1时,在这里插入图片描述

通项公式
数论之素数及其相关定理_第2张图片

p1,p2…pn为x的质因子

2、欧拉函数算法

int oula(int n){
	int rea=n;
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			rea=rea - rea/i;
			while(n%i==0){
				n/=i;
			}
		}
	}
	if(n>1) rea=rea-rea/n;
	return rea;
}

3、欧拉打表

1.埃氏筛法打表

void getPhi(){
	for(int i=1;i<maxn;i++){
		p[i]=i;
	}
	for(int i=2;i<maxn;i++){
		if(p[i]==i){
			for(int j=i;j<maxn;j+=i){
				p[j]=(p[j]/i)*(i-1);
			}
		}
	}
}

2.欧氏筛法打表

void getPhi(){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!flag[i]){
			prime[++tot]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=tot;j++){
			if(i*prime[j]>n) break;
			flag[i*prime[j]]=1;
			if(i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
}

你可能感兴趣的:(算法学习)