扩展欧几里得算法及其应用

扩展欧几里得算法是欧几里得算法(又叫辗转相除法)的扩展。

文章目录

  • 1 前言
  • 2 扩展欧几里得算法(求方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 的解)
    • 裴蜀定理
  • 3 求方程 a x + b y = c ax+by=c ax+by=c 的解
  • 4 同余式 a x ≡ c ( m o d   m ) ax\equiv c(mod\ m) axc(mod m) 的求解
  • 5 逆元的求解以及 ( b / a ) % m (b/a)\% m (b/a)%m

1 前言

本文主要介绍扩展欧几里得算法的原理和实现,以及其四个应用:方程 a x + b y = c ax+by=c ax+by=c 的求解,同余式 a x ≡ c ( m o d   m ) ax \equiv c(mod\ m) axc(mod m) 的求解,逆元的求解、 ( b / a ) (b / a) % m (b/a) 的计算。主要参考 《算法笔记》胡凡 5.7扩展欧几里得算法这一章节,并做了自己的修改使得内容更易理解。对于辗转相除法有疑惑的读者可以参考:PAT OJ 刷题必备知识总结。

2 扩展欧几里得算法(求方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 的解)

扩展欧几里得算法是欧几里得算法辗转相除法)的扩展,它用来解决这么一个问题:求一组非零整数解 ( x , y ) (x, y) (x,y) 使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 成立, g c d ( a , b ) gcd(a,b) gcd(a,b) 表示 a a a b b b 的最大公约数。由裴蜀定理可知这个方程是一定有解的,相关介绍和证明放在本节之后。由于最大公约数是一个定值,因此在下文统一用 g c d gcd gcd 来表示 g c d ( a , b ) gcd(a,b) gcd(a,b)

// 欧几里得算法,又称辗转相除法
int gcd(int a, int b)
{
    if (b == 0) return a;
    else return gcd(b, a % b);
}

欧几里得算法在求解 g c d ( a , b ) gcd(a,b) gcd(a,b) 时,会转化为求解 g c d ( b , a % b ) gcd(b,a\%b) gcd(b,a%b)。当 b b b 的值为0时算法结束(到达递归的边界),此时返回的 a a a 就是最大公约数 g c d gcd gcd。在这时我们可以找到解 x = 1 , y = 0 x = 1, y = 0 x=1,y=0 使得方程 a x + b y = g c d ax + by=gcd ax+by=gcd 成立,可以利用这个解来反推其他的整数解。

假设存在解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 满足下面的方程组:

{     a x 1 + b y 1 = g c d ( a , b ) b x 2 + ( a % b ) y 2 = g c d ( b , a % b ) \left\{\begin{array}{} \ \ \ ax_1+by_1=gcd(a,b) \\bx_2+(a\%b)y_2=gcd(b,a\%b) \end{array}\right. {   ax1+by1=gcd(a,b)bx2+(a%b)y2=gcd(b,a%b)

因为 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b),同时 a % b = a − ⌊ a b ⌋ ∗ b a\%b = a-\left \lfloor \frac{a}{b} \right \rfloor *b a%b=abab ⌊ a b ⌋ \left \lfloor \frac{a}{b} \right \rfloor ba 表示向下取整,例如 ⌊ 81 6 ⌋ = 13 \left \lfloor \frac{81}{6} \right \rfloor = 13 681=13),因此可以联立得到:

a x 1 + b y 1 = b x 2 + ( a − a b ∗ b ) y 2 ax_1+by_1 = bx_2+(a-\frac{a}{b}*b)y_2 ax1+by1=bx2+(abab)y2

合并右侧同类项得:

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-\frac{a}{b}y_2) ax1+by1=ay2+b(x2bay2)

由待定系数法知:

{ x 1 = y 2 y 1 = x 2 − a b y 2 \left\{\begin{array}{l}x_1=y_2 \\y_1=x_2-\frac{a}{b}y_2\end{array}\right. {x1=y2y1=x2bay2

因此我们可以通过 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 得到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 。由于欧几里得算法使用递归实现,要计算 g c d ( a , b ) gcd(a,b) gcd(a,b),需要先计算 g c d ( b , a % b ) gcd(b,a\%b) gcd(b,a%b),放在算法中实现,只需要在到达递归边界、不断退出当前层时根据上述公式即可计算出上一层的解 ( x , y ) (x,y) (x,y)。代码如下:

int extendedGcd(int a, int b, int &x, int &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	int gcd = extendedGcd(b, a % b, x, y);	// 递归
	int temp = x;
	x = y;					// x1 = y2
	y = temp - a / b * y;	// y1 = x1 - a / b * y1
	
	return gcd;				// 返回最大公约数
}

因为使用的是引用,因此算法结束时的 ( x , y ) (x,y) (x,y) 就是使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 成立的解。那能否有一个更通用的公式,来求出每一层递归的解呢?不妨推导一下,假设每一层递归的解是 ( x + s 1 , y − s 2 ) (x+s_1,y-s_2) (x+s1,ys2),其中 s 1 s_1 s1 s 2 s_2 s2 可以是任何整数。将新解代入方程,联立可以得到方程组:

{ a ∗ ( x + s 1 ) + b ∗ ( y − s 2 ) = g c d a x + b y = g c d \left\{\begin{array}{r}a*(x+s_1)+b*(y-s_2)=gcd\\ax+by=gcd\end{array}\right. {a(x+s1)+b(ys2)=gcdax+by=gcd

解得 a s 1 = b s 2 as_1=bs_2 as1=bs2,于是有 s 1 s 2 = b a \frac{s_1}{s_2} = \frac{b}{a} s2s1=ab。又因为 b g c d \frac{b}{gcd} gcdb a g c d \frac{a}{gcd} gcda 互质且都为整数,所以可以进一步约分为 s 1 s 2 = b a = b / g c d a / g c d \frac{s_1}{s_2} = \frac{b}{a} = \frac{b/gcd}{a/gcd} s2s1=ab=a/gcdb/gcd,所以 s 1 s_1 s1 s 2 s_2 s2 的最小取值是 b g c d \frac{b}{gcd} gcdb a g c d \frac{a}{gcd} gcda。由此便可以得到一个更通用的公式,或者说是通解:

{ x ′ = x + b g c d ∗ K y ′ = y − a g c d ∗ K ( K 为任意整数 ) \left\{\begin{array}{l} x'=x+\frac{b}{gcd}*K \\\\y'=y-\frac{a}{gcd}*K \end{array}\right.(K 为任意整数) x=x+gcdbKy=ygcdaK(K为任意整数)

上式中 ( x , y ) (x,y) (x,y) 是使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 成立的解,已由 extendedGcd() 函数得到。

互质是指两个数除了1以外没有其他的公因子。在这里,假设 b g c d \frac{b}{gcd} gcdb a g c d \frac{a}{gcd} gcda 存在除了1以外的公因子 m m m,那么 b g c d ∗ m \frac{b}{gcd*m} gcdmb a g c d ∗ m \frac{a}{gcd*m} gcdma 也会是整数,而 b g c d ∗ m ∗ ( g c d ∗ m ) = b , a g c d ∗ m ∗ ( g c d ∗ m ) = a \frac{b}{gcd*m} * (gcd * m) = b,\frac{a}{gcd*m} * (gcd * m) = a gcdmb(gcdm)=b,gcdma(gcdm)=a,从而 a a a b b b 的最大公约数就成了 g c d ∗ m gcd * m gcdm,这与 g c d gcd gcd 是最大公约数这一前提是矛盾的,因此 b g c d \frac{b}{gcd} gcdb a g c d \frac{a}{gcd} gcda 是一定互质的。

综上,由通解可知 x ′ x' x y ′ y' y 分别以 b g c d \frac{b}{gcd} gcdb a g c d \frac{a}{gcd} gcda 为周期。其中 x ′ x' x最小非负整数解是多少呢?从公式看应该是 x x x 最大程度上地减去 b g c d \frac{b}{gcd} gcdb 的整数倍,最后得到 x % b g c d x\% \frac{b}{gcd} x%gcdb(不理解的读者可以这么想:这不就是除法的过程吗?)。

但是通过 extendedGcd() 函数算出来的 x x x y y y可正可负的,因此 x % b g c d x\% \frac{b}{gcd} x%gcdb 有可能会得到一个负数,例如 ( − 17 ) % 5 = − 2 (-17)\%5 = -2 (17)%5=2。但即便 x x x 是一个负数, x % b g c d x\% \frac{b}{gcd} x%gcdb 的范围也是在 ( − b g c d , 0 ) (-\frac{b}{gcd},0) (gcdb,0),因此 ( x % b g c d + b g c d ) % b g c d (x\% \frac{b}{gcd}+ \frac{b}{gcd})\% \frac{b}{gcd} (x%gcdb+gcdb)%gcdb 才是对应的最小非负整数解,原因如下:

  • x x x 是一个负数, x % b g c d x\% \frac{b}{gcd} x%gcdb 加上 b g c d \frac{b}{gcd} gcdb 后它就成为了正数。且小于 b g c d \frac{b}{gcd} gcdb
  • x x x 是一个正数, x % b g c d x\% \frac{b}{gcd} x%gcdb 加上 b g c d \frac{b}{gcd} gcdb 后会超过 b g c d \frac{b}{gcd} gcdb,所以需要取余,从而其限制在 b g c d \frac{b}{gcd} gcdb 之内。

特别地,当 g c d = 1 gcd=1 gcd=1,即 a x + b y = 1 ax+by = 1 ax+by=1 时,通解公式就可以简化为下式,且 x x x 的最小非负整数也可以化简为 ( x % b + b ) % b (x\%b+b)\%b (x%b+b)%b

{ x ′ = x + b ∗ K y ′ = y − a ∗ K ( K 为任意整数 ) \left\{\begin{array}{l} x'=x+b*K \\y'=y-a*K \end{array}\right.(K为任意整数) {x=x+bKy=yaK(K为任意整数)

裴蜀定理

首先补充一个概念:若 a a a 能被 b b b 整除,或者说 a % b = 0 a \% b = 0 a%b=0,亦或者说 a / b a/b a/b 的结果是一个整数,就可以记作 b ∣ a b|a ba,即“ b b b 能整除 a a a”或者“ a a a 能被 b b b 整除”。

在数论中,裴蜀定理是一个关于最大公约数(或最大公约式)的定理。裴蜀定理是这么说的:若 a a a b b b 是整数, g c d ( a , b ) gcd(a,b) gcd(a,b) 是它们的最大公约数,那么对于任意的整数 x x x y y y a x + b y ax+by ax+by 都一定是 g c d ( a , b ) gcd(a,b) gcd(a,b) 的倍数。简单来说, a x + b y = m ( a , b , m ∈ Z ) ax+by=m(a,b,m\in Z) ax+by=m(a,b,mZ) 存在整数解的充要条件是 g c d ( a , b ) ∣ m gcd(a,b)|m gcd(a,b)m,即 m m m 能被 g c d ( a , b ) gcd(a,b) gcd(a,b) 整除。

特别的,一定存在整数解 x x x y y y,使得 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) 成立。

比如说 36 x + 14 y = 36 36x+14y=36 36x+14y=36 是一定有解的,因为36和14的最大公约数是2,而36是2的倍数。由此也能得到裴蜀定理的一个重要推论:若 a a a b b b 互质,则 a x + b y = m ax+by=m ax+by=m 必定有整数解。因为当 a a a b b b 互质时,最大公约数为1,而整数 m m m 是1的倍数,所以有整数解。

裴蜀定理的证明如下:

对于不全为0的整数 a a a b b b,设 A = { a x + b y ∣ x , y ∈ Z } A=\{ax+by|x,y\in Z\} A={ax+byx,yZ},即所有 a a a b b b 的线性组合组成的数的集合 。假设集合 A A A最小正值 s = a x 2 + b y 2 s = ax_2+by_2 s=ax2+by2,对于任意一个整数 n = ( a x 1 + b y 1 ) ∈ A n = (ax_1+by_1)\in A n=(ax1+by1)A,令 q = ⌊ n s ⌋ q = \left \lfloor \frac{n}{s} \right \rfloor q=sn,则有:

r = n   m o d   s = n − q s = ( a x 1 + b y 1 ) − q ( a x 2 + b y 2 ) = a ( x 1 − q x 2 ) + b ( y 1 − q y 2 ) r = n\ mod\ s= n-qs=(ax_1+by_1)-q(ax_2+by_2)=a(x_1-qx_2)+b(y_1-qy_2) r=n mod s=nqs=(ax1+by1)q(ax2+by2)=a(x1qx2)+b(y1qy2)

由此可知 r = n   m o d   s r = n\ mod\ s r=n mod s 也是 a a a b b b 的线性组合,所以 r ∈ A r\in A rA 。又因为 0 ≤ r < s 0\leq r < s 0r<s,所以 n n n 一定能被 s s s 整除,否则 r r r 就成了 A A A 中的最小正值,这与 s s s 的定义是相矛盾的,故 s ∣ n s|n sn

又因为 a , b ∈ A a,b\in A a,bA,由 n n n 的任意性可知 s ∣ a s|a sa s ∣ b s|b sb,故 s s s a a a b b b 的公因子,设 a a a b b b 的最大公约数为 d = g c d ( a , b ) d = gcd(a,b) d=gcd(a,b),则有 d ≥ s d\ge s ds

因为 s s s a a a b b b 的线性组合,由 s d = a x 2 + b y 2 d = a d x 2 + b d y 2 \frac{s}{d} = \frac{ax_2+by_2}{d} = \frac{a}{d}x_2+\frac{b}{d}y_2 ds=dax2+by2=dax2+dby2 是一个整数可知 d ∣ s d|s ds,又因为 s > 0 s>0 s>0,所以有 d ≤ s d\le s ds,从而可以证得 d = s d = s d=s

综上可知 s s s a a a b b b 的最大公约数,由此可推得 a a a b b b 的所有线性组合 a x + b y ax+by ax+by 中,最小的是最大公约数 g c d ( a , b ) gcd(a,b) gcd(a,b),而所有的线性组合都能够被 g c d ( a , b ) gcd(a,b) gcd(a,b) 整除。

3 求方程 a x + b y = c ax+by=c ax+by=c 的解

扩展欧几里得算法的一个应用就是求解 a x + b y = c ax+by=c ax+by=c c c c 为任意整数。假设由 a x + b y = g c d ax+by=gcd ax+by=gcd 解得 ( x , y ) = ( x 0 , y 0 ) (x,y)=(x_0,y_0) (x,y)=(x0,y0),当 c % g c d = 0 c\%gcd = 0 c%gcd=0 时,在等号两边同时乘以 c g c d \frac{c}{gcd} gcdc,则有 a c x 0 g c d + b c y 0 g c d = c a\frac{cx_0}{gcd}+b\frac{cy_0}{gcd} = c agcdcx0+bgcdcy0=c 成立,因此 ( x , y ) = ( c x 0 g c d , c y 0 g c d ) (x,y) = (\frac{cx_0}{gcd},\frac{cy_0}{gcd}) (x,y)=(gcdcx0,gcdcy0) a x + b y = c ax+by=c ax+by=c 的一组解。能这么做的前提是 c % g c d = 0 c\%gcd = 0 c%gcd=0,否则后者方程不一定有解。

但是两边乘上 c % g c d = 0 c\%gcd = 0 c%gcd=0 得到的只是一部分解,我们仍然需要推导通解公式。采用上一小节一样的方法,设新解为 x + s 1 x + s_1 x+s1 y − s 2 y-s_2 ys2,联立如下方程组:

{ a ∗ ( x + s 1 ) + b ∗ ( y − s 2 ) = g c d a x + b y = g c d \left\{\begin{array}{r}a*(x+s_1)+b*(y-s_2)=gcd\\ax+by=gcd\end{array}\right. {a(x+s1)+b(ys2)=gcdax+by=gcd

依然能得到下面的解,将 x , y x,y x,y ( c x 0 g c d , c y 0 g c d ) (\frac{cx_0}{gcd},\frac{cy_0}{gcd}) (gcdcx0,gcdcy0) 替换后就可得到一个通解:

{ x ′ = x + b g c d ∗ K = c x 0 g c d + b g c d ∗ K y ′ = y − a g c d ∗ K = c y 0 g c d − a g c d ∗ K ( K 为任意整数 ) \left\{\begin{array}{l} x'=x+\frac{b}{gcd}*K = \frac{cx_0}{gcd}+ \frac{b}{gcd}*K \\\\y'=y-\frac{a}{gcd}*K = \frac{cy_0}{gcd} - \frac{a}{gcd}*K \end{array}\right.(K 为任意整数) x=x+gcdbK=gcdcx0+gcdbKy=ygcdaK=gcdcy0gcdaK(K为任意整数)

可以看到这个通解与 a x + b y = g c d ax+by=gcd ax+by=gcd 的通解是一样的,区别只有初始解不一样。为什么乘上 c g c d \frac{c}{gcd} gcdc 只能获得一部分的解呢?由于 c ≥ g c d c\ge gcd cgcd,因为 a x + b y = g c d ax+by=gcd ax+by=gcd 的通解乘以 c g c d \frac{c}{gcd} gcdc 会导致周期放大为原先的 c g c d \frac{c}{gcd} gcdc 倍从而漏解。

同样的可以得出结论:对任意整数来说, ( c x 0 g c d % b g c d + b g c d ) % b g c d (\frac{cx_0}{gcd}\% \frac{b}{gcd}+ \frac{b}{gcd})\% \frac{b}{gcd} (gcdcx0%gcdb+gcdb)%gcdb a x + b y = g c d ax+by=gcd ax+by=gcd x x x 的最小非负整数解,其中 x 0 x_0 x0 a x + b y = g c d ax+by=gcd ax+by=gcd 一个解。并且,如果 g c d = 1 gcd = 1 gcd=1,那么全部解的公式可以化简为下式,且 x x x 的最小非负整数解就可以简化为 ( c x 0 % b + b ) % b (cx_0\% b+b)\%b (cx0%b+b)%b

{ x ′ = c x 0 + b ∗ K y ′ = c y 0 − a ∗ K ( K 为任意整数 ) \left\{\begin{array}{l} x'= cx_0+ b*K \\\\y'= cy_0 - a*K \end{array}\right.(K 为任意整数) x=cx0+bKy=cy0aK(K为任意整数)

4 同余式 a x ≡ c ( m o d   m ) ax\equiv c(mod\ m) axc(mod m) 的求解

同余式:对于整数 a a a b b b m m m 来说,如果 m m m 能够整除 a − b a-b ab,即 ( a − b ) % m = 0 (a-b)\% m = 0 (ab)%m=0,那么就说 a a a b b b m m m 同余,写作 a ≡ b ( m o d   m ) a\equiv b(mod\ m) ab(mod m)。例如10与13模3同余,10也与1模3同余,分别写作 10 ≡ 13 ( m o d   3 ) 10\equiv 13(mod\ 3) 1013(mod 3) 10 ≡ 1 ( m o d   3 ) 10\equiv 1(mod\ 3) 101(mod 3)。显然,每一个整数都各自与 [ 0 , m ) [0,m) [0,m) 中唯一的整数同余。

要求解 a x ≡ c ( m o d   m ) ax\equiv c(mod\ m) axc(mod m),根据同余式的定义可知 ( a x − c ) % m = 0 (ax-c)\%m = 0 (axc)%m=0,因此存在整数 y y y 使得 a x − c = m y ax-c=my axc=my 成立。移项并令 y = − y y=-y y=y 后就可以得到 a x + m y = c ax+my=c ax+my=c,这就回到了上一小节的问题了。依然可以先由 a x + m y = g c d ( a , m ) ax+my = gcd(a,m) ax+my=gcd(a,m) 得到一个解 (x_0,y_0),再由公式 ( x , y ) = ( c x 0 g c d ( a , m ) , c y 0 g c d ( a , m ) ) (x,y)=(\frac{cx_0}{gcd(a,m)},\frac{cy_0}{gcd(a,m)}) (x,y)=(gcd(a,m)cx0,gcd(a,m)cy0) 直接得到通解:

{ x ′ = c x 0 g c d ( a , m ) + m g c d ( a , m ) ∗ K y ′ = c y 0 g c d ( a , m ) − a g c d ( a , m ) ∗ K ( K 为任意整数 ) \left\{\begin{array}{l} x'=\frac{cx_0}{gcd(a,m)}+\frac{m}{gcd(a,m)}*K \\\\y'=\frac{cy_0}{gcd(a,m)}-\frac{a}{gcd(a,m)}*K \end{array}\right.(K 为任意整数) x=gcd(a,m)cx0+gcd(a,m)mKy=gcd(a,m)cy0gcd(a,m)aK(K为任意整数)

综上,设 a a a b b b m m m 是整数,其中 m ≥ 1 m\ge 1 m1,则:

  • c % g c d ( a , m ) ≠ 0 c\% gcd(a,m)\ne 0 c%gcd(a,m)=0,则同余式 a x ≡ c ( m o d   m ) ax\equiv c(mod\ m) axc(mod m) 无解。
  • c % g c d ( a , m ) = 0 c\% gcd(a,m)= 0 c%gcd(a,m)=0,则同余式 a x ≡ c ( m o d   m ) ax\equiv c(mod\ m) axc(mod m) 方程恰好有 g c d ( a , m ) gcd(a,m) gcd(a,m) 个模 m m m 意义下不同的解,且解为 x ′ = c x 0 g c d ( a , m ) + m g c d ( a , m ) ∗ K x'=\frac{cx_0}{gcd(a,m)}+\frac{m}{gcd(a,m)}*K x=gcd(a,m)cx0+gcd(a,m)mK其中 K = 0 , 1 , . . . , g c d ( a , m ) − 1 K=0,1,...,gcd(a,m) - 1 K=0,1,...,gcd(a,m)1 c x 0 g c d ( a , m ) \frac{cx_0}{gcd(a,m)} gcd(a,m)cx0 a x + m y = c ax+my=c ax+my=c 的一个解。

5 逆元的求解以及 ( b / a ) % m (b/a)\% m (b/a)%m

逆元:假设 a a a b b b m m m 是整数, m > 1 m>1 m>1,且有 a b ≡ 1 ( m o d   m ) ab\equiv 1(mod\ m) ab1(mod m) 成立,那么就说 a a a b b b 互为模 m m m 的逆元,一般也写作 a ≡ 1 b ( m o d   m ) a\equiv \frac{1}{b}(mod\ m) ab1(mod m) b ≡ 1 a ( m o d   m ) b\equiv \frac{1}{a}(mod\ m) ba1(mod m)

逆元有什么用呢?对乘法来说有 ( b ∗ a ) % m = ( ( b % m ) ∗ ( a % m ) ) % m (b*a)\% m = ((b\% m)*(a\% m))\% m (ba)%m=((b%m)(a%m))%m 成立,但是对除法来说, ( b / a ) % m = ( ( b % m ) / ( a % m ) ) % m (b/a)\% m = ((b\% m)/(a\% m))\% m (b/a)%m=((b%m)/(a%m))%m 却不成立, ( b / a ) % m = ( ( b % m ) / a ) % m (b/a)\% m = ((b\% m)/a)\% m (b/a)%m=((b%m)/a)%m 也不成立。此时就可以通过逆元来计算 ( b / a ) % m (b/a)\% m (b/a)%m。通过找到 a a a m m m 的逆元 x x x,就有 ( b / a ) % m = ( b ∗ x ) % m = ( ( b % m ) ∗ ( x % m ) ) % m (b/a)\% m=(b*x)\% m = ((b\% m)*(x\% m))\% m (b/a)%m=(bx)%m=((b%m)(x%m))%m 成立,于是就把除法取模转化为了乘法取模,这对于解决被除数 b b b 非常大的问题来说是非常好用的。

由定义知,求 a a a m m m 的逆元,就是求解同余式 a x ≡ 1 ( m o d   m ) ax\equiv 1(mod\ m) ax1(mod m),并且在实际使用中,一般把 x x x最小正整数(注意和最小非负整数区分开,最小正整数不包含0)解称为 a a a m m m 的逆元,因此下文中提到的逆元都默认为 x x x 的最小正整数解。显然,同余式 a x ≡ 1 ( m o d   m ) ax\equiv 1(mod\ m) ax1(mod m) 是否有解取决于 1 % g c d ( a , m ) 1\% gcd(a,m) 1%gcd(a,m) 是否为0,二这等价于求 g c d ( a , m ) gcd(a,m) gcd(a,m) 是否为1:

  • 如果 g c d ( a , m ) ≠ 1 gcd(a,m)\ne 1 gcd(a,m)=1,那么同余式 a x ≡ 1 ( m o d   m ) ax\equiv 1(mod\ m) ax1(mod m) 无解,不存在模 m m m 的逆元。
  • 如果 g c d ( a , m ) = 1 gcd(a,m) = 1 gcd(a,m)=1,那么同余式 a x ≡ 1 ( m o d   m ) ax\equiv 1(mod\ m) ax1(mod m) ( 0 , m ) (0,m) (0,m) 上有唯一解,并且可以通过求解 a x + m y = 1 = g c d ( a , m ) ax+my=1=gcd(a,m) ax+my=1=gcd(a,m) 得到。直接使用扩展欧几里得算法解出 x x x 之后就可以用 ( x % m + m ) % m (x\% m + m)\% m (x%m+m)%m 得到 ( 0 , m ) (0,m) (0,m) 范围内的解,也就是所需要的逆元。

下面的代码使用了扩展欧几里得算法来求解 a a a m m m 的逆元,使用条件是 g c d ( a , m ) = 1 gcd(a,m)= 1 gcd(a,m)=1,当然如果 m m m 是素数,就肯定成立了,可以放心使用。

int inverse(int a, int m)
{
	int x, y;
	int g = extendedGcd(a, m, x, y);	// 求解 ax + my = 1
	return (x % m + m) % m;				// a 模 m 的逆元
}

另外,如果 m m m 是素数,且 a a a 不是 m m m 的倍数,就可以直接使用费马小定理来得到逆元,而不需要使用扩展欧几里得算法。

费马小定理:设 m m m 是素数, a a a 是任意整数且 a a a 不是 m m m 的倍数,则 a m − 1 ≡ 1 ( m o d   m ) a^{m - 1}\equiv 1(mod \ m) am11(mod m)

使用费马小定理来推导逆元:由 a m − 1 ≡ 1 ( m o d   m ) a^{m - 1}\equiv 1(mod \ m) am11(mod m) 可知 a ∗ a m − 2 ≡ 1 ( m o d   m ) a*a^{m-2}\equiv 1(mod\ m) aam21(mod m),又逆元的定义就能知道 a a a m m m 的逆元是 a m − 2 % m a^{m-2}\% m am2%m。另外,当 g c d ( a , m ) ≠ 1 gcd(a,m)\ne 1 gcd(a,m)=1 时,扩展欧几里得算法和费马小定理都不适用了,但此时仍然可以求解 ( b / a ) % m (b/a)\% m (b/a)%m。假设 ( b / a ) % m = x (b/a)\% m=x (b/a)%m=x,因此存在整数 k k k,使得 b / a = k m + x b / a = km + x b/a=km+x。等式两边同时乘以 a a a,得 b = k a m + a x b = kam+ax b=kam+ax,于是有 b % ( a m ) = a x b\%(am)=ax b%(am)=ax。等式两边同时除以 a a a,得 ( b % ( a m ) ) / a = x (b\% (am))/a=x (b%(am))/a=x,于是又 $(b/a)% m = ( b % ( a m ) ) / a (b\% (am))/a (b%(am))/a

因此在 a a a m m m 不互质的情况下,可以用公式 $(b/a)% m = ( b % ( a m ) ) / a (b\% (am))/a (b%(am))/a 来计算 ( b / a ) % m (b/a)\% m (b/a)%m 的值,唯一要注意的是 a a a m m m 的乘积可能会太大而导致溢出。因此一般来说尽量使用扩展欧几里得算法或者费马小定理求解,条件不成立时再采用这种方法。


希望本篇博客能对你有所帮助,也希望看官能动动小手点个赞哟~~。

你可能感兴趣的:(算法与数据结构,算法,数论,欧几里得算法,同余求解,最大公约数)