欧几里得算法-计算a,b最大公约数
计算方法
1.当b≠0时:a=b,b=a%b;
2.当b=0时,最大公约数为a;
算法
int gcd(int a,int b){
return !b?a:gcd(b,a%b);
}
扩展-计算ax+by=gcd(a,b)
方法(其中a,b是在不断变化的)
- 首先计算出gcd=gcd(a,b);
- a x 1 + b y 1 = g c d ax_{1}+by_{1}=gcd ax1+by1=gcd且 b x 2 + ( a % b ) y 2 = g c d bx_{2}+(a\%b)y_{2}=gcd bx2+(a%b)y2=gcd,所以 a x 1 + b y 1 = b x 2 + ( a % b ) y 2 ax_{1}+by_{1}=bx_{2}+(a\%b)y_{2} ax1+by1=bx2+(a%b)y2,又 a % b = a − ( a / b ) ∗ b a\%b=a-(a/b)*b a%b=a−(a/b)∗b,所以整理得到 a x 1 + b y 1 = a y 2 + b ( x 2 − ( a / b ) y 2 ) ax_{1}+by_{1}=ay_{2}+b(x_{2}-(a/b)y_{2}) ax1+by1=ay2+b(x2−(a/b)y2),所以 x 1 = y 2 , y 1 = x 2 − ( a / b ) ∗ y 2 x_{1}=y_{2},y_{1}=x_{2}-(a/b)*y_{2} x1=y2,y1=x2−(a/b)∗y2;
- 这样通过递归计算就可以得到一组解 x , y x,y x,y,此时显然 a ∗ ( x + s 1 ) + b ∗ ( y − s 2 ) = g c d a*(x+s_{1})+b*(y-s_{2})=gcd a∗(x+s1)+b∗(y−s2)=gcd,化简得到 s 1 / s 2 = b / a = ( b / g c d ) / ( a / g c d ) s_{1}/s_{2}=b/a=(b/gcd)/(a/gcd) s1/s2=b/a=(b/gcd)/(a/gcd),所以 x a l l = x + b / g c d ∗ k i , y a l l = y − a / g c d ∗ k i , i = 0 , 1 , 2 , 3 , . . . x_{all}=x+b/gcd*k_{i},y_{all}=y-a/gcd*k_{i},i=0,1,2,3,... xall=x+b/gcd∗ki,yall=y−a/gcd∗ki,i=0,1,2,3,...,可以看出 x a l l , y a l l x_{all},y_{all} xall,yall分别以 b / g c d , a / g c d b/gcd,a/gcd b/gcd,a/gcd为周期,所以最小的正整数 x = ( x % ( b / g c d ) + ( b / g c d ) ) % ( b / g c d ) x=(x\%(b/gcd)+(b/gcd))\%(b/gcd) x=(x%(b/gcd)+(b/gcd))%(b/gcd),(这里是为了保证x为正整数,因为等式右侧的 x x x可能为负数);
代码
int getgcd(int a,int b,int &x,int &y){//这里找出x,y与a和b的最大公约数
if(b==0){
x=1;
y=0;
return a;
}
int g = getgcd(b,a%b,x,y);//获得最大公约数
//递归找到最初的x与y
int temp=x;
x=y;
y=temp-(a/b)*y;
return g;
}
进一步扩展-计算ax+by=c
方法
- 首先我们计算 a x + b y = g c d ( a , b ) = g c d ax+by=gcd(a,b)=gcd ax+by=gcd(a,b)=gcd得 x x x;
- 然后两边同时乘以 c / g c d c/gcd c/gcd得 a x ∗ ( b / g c d ) + b y ∗ ( b / g c d ) = g c d ∗ ( c / g c d ) ax*(b/gcd)+by*(b/gcd)=gcd*(c/gcd) ax∗(b/gcd)+by∗(b/gcd)=gcd∗(c/gcd),(注意到 c % g c d = = 0 c\%gcd==0 c%gcd==0才成立);
- 所以我们由上一个问题可以得到该问题的解 x a l l = x ∗ ( b / g c d ) + b / g c d ∗ k i , y a l l = y ∗ ( b / g c d ) − a / g c d ∗ k i , i = 0 , 1 , 2 , 3 , . . . x_{all}=x*(b/gcd)+b/gcd*k_{i},y_{all}=y*(b/gcd)-a/gcd*k_{i},i=0,1,2,3,... xall=x∗(b/gcd)+b/gcd∗ki,yall=y∗(b/gcd)−a/gcd∗ki,i=0,1,2,3,...;
再次扩展-同余式计算
概念:
a与c模m同余:即(a-b)%m=0;可以写成:ax=c(mod m);
方法
- ( a x − m ) % c = 0 (ax-m)\%c=0 (ax−m)%c=0,可以转化为 a x + c k = m ax+ck=m ax+ck=m,这样就转化成为了上一个问题同样有 m / g c d ( a , m ) = 0 m/gcd(a,m)=0 m/gcd(a,m)=0。此时 x a l l = x + ( m / g c d ) ∗ k x_{all}=x+(m/gcd)*k xall=x+(m/gcd)∗k其中,k的取值只能在0,1,…,m-1中取,否则会被在这个范围内的数取代.
再次扩展-逆元
概念
若a*b=1(mod m),即 ( a ∗ b ) % m = 1 (a*b)\%m=1 (a∗b)%m=1,这样即是同余式中的余数1;这里注意要求gcd(a,m)=1,否则无解,因为此时c/gcd(a,m)=1/gcd(a,m),由第二个问题可得,必然要求gcd(a,m)=1.
扩展
当模m为素数时,所要求的a*b=1(mod m),已知a,且a≠0,则 b = a m − 1 b=a^{m-1} b=am−1。