扩展欧几里德算法是用来在已知
a,b求解一组
x,y,使它们满足贝祖(裴蜀)等式:
ax+by=gcd(a,b)=d
关于贝祖等式
试着来搞一下
ax+by=gcd(a,b)
先考虑一下特殊情况,如果
b=0,那么
gcd(a,b)=a,显然存在一组解
x=1,y=0
设当前的式子为
ax1+by1=gcd(a,b),肯定存在式子
bx2+(a%
b)y2=gcd(b,a%
b)
根据欧几里得算法,
gcd(a,b)=gcd(b,a%
b)
∴ax1+by1=bx2+(a%
b)y2
∵a%
b=a−a/b∗b(这里的除是指整除)
∴ax1+by1=bx2+(a−a/b∗b)y2
ax1+by1=bx2+ay2−a/b∗b∗y2
ax1+by1=ay2+b(x2−a/b∗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);
return y-=a/b*x,d;
}
顺便普及一下逗号运算符,
:在c++中,(a,b,c)==c。也就是说,一堆表达式用逗号连接起来,他们的值就是最后一个表达式的值(巧妙的使用可以使得代码复杂度降低)
当然exgcd不可能只有这么点用途呀,它还可以用来求逆元,并且比用费马小定理
求更方便,比如求
a在模
p意义下的逆元,如果用费马小定理
求的话,还要保证
p是个质数,但是用exgcd就不用了。
怎么求呢?
设
x为
a在模
p意义下的逆元,那么满足式子:
ax≡1
(mod
m)
那么有:
ax+my=1
然后用exgcd搞出
a即可(以及这就是为什么 a和m一定要互质 才能使得
a在模
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)%n:-1;
}