基于数论的常用算法gcd 、ex_gcd,素数

证明就算了吧,弱鸡太懒了,这也可能是为什么我是弱鸡的原因吧,决定记下结论会用就行了。

1、gcd():最大公约数

int gcd(a,b){//算法导论上指出a、b为非负整数,不用在意两者的大小关系
if b==0 return a;
else return gcd( b,a % b)
}//时间复杂度O(log max(a,b))

2、ex_gcd():扩展欧几里得算法

一定存在整数对(x,y)使得ax+by=gcd(a,b)。此处省略一万字数学证明

int extgcd(int a,int b,int x, int y){
	int d =a;
	if(b!=0){
		d = extgcd(b,a%b,y,x);
		y -= (a/b)*x;
	}
	else{
		x=1;
		y=0;
	}
	return d;//返回的是gcd(a,b) ,时间内复杂度同上
} 

3、素数:

1、对于单独判断一个数字是否为素数,只要从2~根号n之间找即可。

2、输出或统计n以内有多少素数时,采用埃式筛法

int prime[n];//n以内的素数打表
bool is_prime[n+1];

//返回n以内素数的个数
int sieve(int n){
	int count=0;
	for(int i=0;i<=n;i++){
		is_prime=true;
	}
	is_prime[0]=is_prime[1]=false;
	for(int i =2;i<=n;i++){
		prime[count++] = i; //题外话,之前一直弄不清这个括号里写++的方式,是先令count=count+1后再把i赋值给prime[count] 
		for (int j =2*i;j<=n;j+=i){
			is_prime[j]=false;
		}
	}
	return count;
} //时间复杂度O(nloglogn)可认为是线性的 

3、求一个区间内的素数个数:

解释一下:因为b内的合数最小质因数一定不消耗国根号b。即先分别做好[2,根号b)的表和[a,b)的表,然后从小的表里筛得素数的同时,将他的倍数从大表中划去即可。

bool is_prime[1000010]; 
bool is_prime_small[1000010];  
  
void segment_sieve(ll a, ll b)  
{  
    for(int i=0; (ll)i*i<b; i++) is_prime_small[i] = true;//i是素数  
    for(int i=0; i<b-a; i++) is_prime[i] = true;  
    //利用0~len代表a~b的数  
    for(int i=2; (ll)i*i<b; i++)  
    {  
        if(is_prime_small[i])  
        {  
            for(int j=i+i; (ll)j*j<b; j+=i)  
                is_prime_small[j] = false; //筛[2,√b)  
            for(ll j=max(2LL, (a+i-1)/i)*i; j<b; j+=i)  
                is_prime[j-a] = false; //筛[a,b)  
            //j代表素数,j-a是将a~b变为0~b-a以便数组好存储  
            //2LL是2的长整形形式,与其比较意思是j最少是i的两倍  
            //((a+i-1)/i)*i得出的是(>=a && %i==0)离a最近的数,其实  
            //也可以写成a%i==0 ? a : (a/i+1)*i  
        }  
    }  
}  



猜你喜欢

转载自blog.csdn.net/ZLucker/article/details/80379488
gcd