扩展欧几里得算法——exgcd

本文详细介绍了扩展欧几里德算法,一种用于解决贝祖等式ax+by=gcd(a,b)的方法。通过递归过程,算法不仅求解等式,还展示了如何利用其求解逆元,特别适用于模数非质数的情况。文章包含算法实现代码及逆元求解示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扩展欧几里德算法是用来在已知 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=aa÷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+(aa÷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+ay2a÷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(x2a÷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=x2a÷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 ax1(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;//不互质就没有逆元
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值