扩展欧几里德算法是用来在已知 a , b a,b a,b求解一组 x , y x,y x,y,使它们满足贝祖(裴蜀)等式: a x + b y = gcd ( a , b ) = d ax+by = \gcd(a, b) =d ax+by=gcd(a,b)=d
试着来搞一下
a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) ax+by=gcd(a,b)
先考虑一下特殊情况,如果 b = 0 b=0 b=0,那么 gcd ( a , b ) = a \gcd(a,b)=a gcd(a,b)=a,并显然存在一组解 x = 1 , y = 0 x=1,y=0 x=1,y=0
设当前的式子为 a x 1 + b y 1 = g c d ( a , b ) ax_1+by_1=gcd(a,b) ax1+by1=gcd(a,b),肯定存在式子 b x 2 + ( a m o d b ) y 2 = gcd ( b , a m o d b ) bx_2+(a\bmod b)y_2=\gcd(b,a\bmod b) bx2+(amodb)y2=gcd(b,amodb)
根据欧几里得算法, gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\bmod b) gcd(a,b)=gcd(b,amodb)
∴ a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 \therefore ax_1+by_1=bx_2+(a\bmod b)y_2 ∴ax1+by1=bx2+(amodb)y2
∵ a m o d b = a − a ÷ b × b \because a\bmod b=a-a\div b\times b ∵amodb=a−a÷b×b
∴
a
x
1
+
b
y
1
=
b
x
2
+
(
a
−
a
÷
b
×
b
)
y
2
\therefore ax_1+by_1=bx_2+(a-a\div b\times b)y_2
∴ax1+by1=bx2+(a−a÷b×b)y2
a
x
1
+
b
y
1
=
b
x
2
+
a
y
2
−
a
÷
b
×
b
×
y
2
ax_1+by_1=bx_2+ay_2-a\div b\times b\times y_2
ax1+by1=bx2+ay2−a÷b×b×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-a\div b\times y_2)
ax1+by1=ay2+b(x2−a÷b×y2)
∴ x 1 = y 2 , y 1 = x 2 − a ÷ b × y 2 \therefore x_1=y_2,y_1=x_2-a\div b\times y2 ∴x1=y2,y1=x2−a÷b×y2
于是就可以愉快的递推下去了
代码很短:
int exgcd(int a,int b,long long &x,long long &y)
{
if(b==0)return x=1,y=0,a;
int d=exgcd(b,a%b,y,x);//d的值实际上就是gcd(a,b),如果不需要的话可以不求
return y-=a/b*x,d;
}
顺便普及一下逗号运算符,
:在C++中,(a,b,c)==c
。也就是说,一堆表达式用逗号连接起来,他们的值就是最后一个表达式的值(巧妙的使用可以使得代码复杂度降低)
当然exgcd不可能只有这么点用途呀,它还可以用来求逆元,并且比用费马小定理
求更方便,比如求
a
a
a 在模
p
p
p 意义下的逆元,如果用费马小定理
求的话,还要保证
p
p
p 是个质数,但是用exgcd就不用了。
怎么求呢?
设
x
x
x 为
a
a
a 在模
p
p
p 意义下的逆元,那么满足式子:
a
x
≡
1
(
m
o
d
m
)
ax \equiv 1\pmod m
ax≡1(modm)
那么有:
a x + m y = 1 ax+my=1 ax+my=1
然后用 e x g c d exgcd exgcd 搞出 x x x 即可(以及这就是为什么 a a a 和 m m m 一定要互质 才能使得 a a a 在模 m m m 意义下有逆元)
以及逆元的代码在此:
long long inv(long long a,long long m)
{
long long x,y;
long long d=exgcd(a,m,x,y);
return d==1?(x+m)%m:-1;//不互质就没有逆元
}