先是最简单的最大公因数, 通常情况下我们用辗转相除法, 有两种实现方法. 使用辗转相除法的原理参见维基百科.
方法一:循环
long long int _gcd(long long int a,long long int b)
{
if(a==0||b==0)
return 0;
long long int res;
res=a%b;
while(res)
{
a=b;
b=res;
res=a%b;
}
return b;
}
方法二:函数递归
long long int _gcd(long long int a,long long int b)
{
return b?gcd(b,a%b):a;
}
还有一个函数 __gcd, 据说是编译器自带的, 但是仅限于部分编译器, 比如在杭电上面选G++有这个函数, 但是选C++会返回Compile Error.
然后就是求最小公倍数啦, 公式是 lcm( x , y ) = x * y / gcd( x , y ), 因此有函数如下
long long int _lcm(long long int a,long long int b)
{
long long int res;
res=a/_gcd(a,b);
res=res*b;
return res;
}
然后就是求多个数的gcd和lcm啦
long long int gcd_multi(long long int a[],long long int n)
{//a表示存储了这些数字的数组, n表示数字个数
long long int res,i;
res=a[0];
for(i=1;i<n;i++)
{
res=_gcd(res,a[i]);
}
return res;
}
long long int lcm_multi(long long int a[],long long int n)
{//a表示存储了这些数字的数组, n表示数字个数
long long int res,i,g;
res=1;
g=gcd_multi(a,n);
for(i=0;i<n;i++)
{
res=res*a[i];
res=res/g;
}
res=res*g;
return res;
}
然后就是拓展欧几里得.
拓展欧几里得通常用于解形似这个样子的二元一次方程(的一个特解)
a * x + b * y = gcd( a , b )
因此, 当然了, 这样子的方程也是可以解的 a * x + b * y = c = k * gcd( a , b ) 其中, k是一个常数
你只需要先解 a * x + b * y = gcd( a , b ) 的一组 x` 和 y`, 然后 k * x` 和 k * y` 就是a * x + b * y = c 的一组特解
模板如下:
void exgcd(long long int a,long long int b,long long int *x,long long int *y)
{//仅用来解a*x+b*y=gcd(a,b)
if(b==0)
{
*x=1;
*y=0;
return;
}
exgcd(b,a%b,x,y);
long long int temp;
temp=*x;
*x=*y;
*y=temp-(a/b)**y;
}
void exgcd_all(long long int a,long long int b,long long int *x,long long int *y,long long int c)
{//可以用来解a*x+b*y=c=k*gcd(a,b),k是一个整数
//方程a*x+b*y=c,有解的情况是:c%gcd(a,b)=0
if(c==0)
{
*x=*y=0;//手动笑哭
return;
}
long long int g;
g=gcd(a,b);
exgcd(a,b,x,y);
*x=*x*(c/g);
*y=*y*(c/g);
}
引入一个(乘法)逆元的概念, 比如我想求一个数被除以一个数再取余, 很明显你不能先把分子取余再除以分母, 然后不知道哪个人想了个办法把它变成了乘---你可以求一个分母的逆元, 然后将分子乘以这个逆元之后, 再取余, 就是你想要的结果了.
(a*b)%m==1, 我们称b 是 a 关于 1 模 m 的乘法逆元
怎么求?
化一下, 会变成 a * b + m * k = 1, 其中 k 等于多少都无所谓, 只要求得出 b 就行.
是不是跟刚刚的 a * x + b * y = 1长得颇像?
话不多说, 模板如下:
long long int niyuan(long long int a,long long int m)
{
int x,y,g,res;
g=gcd(a,m);
exgcd(a,m,&x,&y);
if(1%g!=0)
return -1;
x=x*1/g;
m=abs(m);
res=(x%m+m)%m;
return res;
}