扩展欧几里得算法及应用

欧几里得算法

即利用辗转相除法求最大公因数

ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
裴蜀定理(贝祖定理)

a , b a,b 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)成立

重要推论: a a a b b b互质的充要条件是存在整数 x , y x,y x,y,有 a x + b y = 1 ax+by=1 ax+by=1

扩展欧几里得算法

扩展欧几里得算法又称 e x g c d exgcd exgcd,就是利用欧几里得算法,求出贝祖定理 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的整数解

证明:

∵ g c d ( a , b ) = g c d ( b , a % b ) , g c d ( b , a % b ) = b x + ( a % b ) y ∵gcd(a,b)=gcd(b,a\%b),gcd(b,a\%b)=bx+(a\%b)y gcd(a,b)=gcd(b,a%b),gcd(b,a%b)=bx+(a%b)y

∴ a 1 x 1 + b 1 y 1 = g c d ( a 1 , b 1 ) = g c d ( b 1 , a 1 % b 1 ) = b 1 x 2 + ( a 1 % b 1 ) y 2 ∴a_1x_1+b_1y_1=gcd(a_1,b_1)=gcd(b_1,a_1\%b_1)=b_1x_2+(a_1\%b_1)y_2 a1x1+b1y1=gcd(a1,b1)=gcd(b1,a1%b1)=b1x2+(a1%b1)y2

a 2 = b 1 , b 2 = a 1 % b 1 a_2=b_1,b_2=a_1\%b_1 a2=b1,b2=a1%b1

∴ a 1 x 2 + b 2 y 2 = g c d ( a 2 , b 2 ) = g c d ( b 2 , a 2 % b 2 ) ) = b 2 x 3 + ( a 2 % b 2 ) y 3 ∴a_1x_2+b_2y_2=gcd(a_2,b_2)=gcd(b_2,a_2\%b_2))=b_2x_3+(a_2\%b_2)y_3 a1x2+b2y2=gcd(a2,b2)=gcd(b2,a2%b2))=b2x3+(a2%b2)y3

同理…

最后可化简为 g c d ( a n , 0 ) = a n x n + 0 ∗ y n = a n gcd(a_n,0)=a_nx_n+0*y_n=a_n gcd(an,0)=anxn+0yn=an

得到最后一组解为 x n = 1 , y n = 0 x_n=1,y_n=0 xn=1,yn=0

∵ a % b = a − ⌊ a b ⌋ ∗ b ∵a\%b=a-\lfloor\frac{a}{b}\rfloor*b a%b=abab,又因为第一次我们化简的等式中有 a 1 x 1 + b 1 y 1 = b 1 x 2 + ( a 1 % b 1 ) y 2 a_1x_1+b_1y_1=b_1x_2+(a_1\%b_1)y_2 a1x1+b1y1=b1x2+(a1%b1)y2

∴ a 1 x 1 + b 1 y 1 = b 1 x 2 + ( a 1 − a 1 / b 1 ∗ b 1 ) y 2 = a 1 y 2 + b 1 ( x 2 − a 1 / b 1 ∗ y 2 ) ∴a_1x_1+b_1y_1=b_1x_2+(a_1-a_1/b_1*b_1)y_2=a_1y_2+b_1(x_2-a_1/b_1*y_2) a1x1+b1y1=b1x2+(a1a1/b1b1)y2=a1y2+b1(x2a1/b1y2)

∴ x 1 = y 2 , y 1 = x 2 − a 1 / b 1 ∗ y 2 ∴x_1=y_2,y_1=x_2-a_1/b_1*y_2 x1=y2,y1=x2a1/b1y2

然后由最后一组解回溯,即可求得 x 1 , y 1 x_1,y_1 x1,y1

下面的代码中是简洁版本:我们都是由下一层得到上一层的,当我们由最后一层返回倒数第二层的时候,我们把 y y y传给上一层的 x x x,这样由上面公式来看是正确结果,而上一层的 y y y怎么求呢,上一层的 y y y等于下一层的 x x x减去 a / b a/b a/b乘以下一层的 y y y。而下一层的 y y y我们已经赋值给了当前层的 x x x,下一层的 x x x我们已经赋值给了当前层的 y y y,因此仔细思考, y − = ( a / b ) ∗ x y-=(a/b)*x y=(a/b)x;就可以得到当前层的 y y y,再一层层向上传递即可

代码之所以返回 a , b a,b a,b的最大公因数是因为我们可能用到,这样就不需要再求一遍 g c d gcd gcd

ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    ll gcd=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return gcd;     //返回的是a,b的最大公因数
}
应用

1.求解二元一次不定方程

已知 a x + b y = c ax+by=c ax+by=c,设 r = g c d ( a , b ) r=gcd(a,b) r=gcd(a,b),则

  • c % r ! = 0 c\%r!=0 c%r!=0,该方程组无整数解

  • c % r = = 0 c\%r==0 c%r==0,我们可以先求出 a x + b y = r ax+by=r ax+by=r对应的一组整数解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),然后再乘以 c c c并除以 r r r即可得到 a x + b y = c ax+by=c ax+by=c的最小整数解 x 0 = x 1 ∗ c / r , y 0 = y 1 ∗ c / r x_0=x_1*c/r,y_0=y_1*c/r x0=x1c/r,y0=y1c/r,那么其通解为 x = x 0 + k ∗ ( b / r ) , y = y 0 − k ∗ ( a / r ) x=x_0+k*(b/r),y=y_0-k*(a/r) x=x0+k(b/r),y=y0k(a/r) k k k取任意整数

2.求逆元

a ∗ x a*x ax在模 p p p意义下的结果为 1 1 1,那么称 x x x a a a在模 p p p意义下的逆元, x x x又写作 a − 1 a^{-1} a1记作 a x ≡ 1 ( m o d    p ) ax≡1(mod~~p) ax1(mod  p)

那么我们可以转化为求解 a x + p y = 1 ax+py=1 ax+py=1,由于最后的求得的 x x x可能是负数,因此我们再进行处理 ( x % p + p ) % p (x\%p+p)\%p (x%p+p)%p

int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return gcd;     //返回的是a,b的最大公因数
}

int inv(int a,int p){
	int x,y;
	exgcd(a,p,x,y);
    return (x%p+p)%p;
}

3.求解线性同余方程

已知线性同余方程 a x ≡ b ( m o d    p ) ax ≡ b (mod~~ p) axb(mod  p) ,则该同余方程可以化为求解二元一次不定方程$ ax+py=b , 设 ,设 r=gcd(a,p)$

显然当且仅当 b % r = = 0 b\%r==0 b%r==0时方程组有解

我们先求 a x + p y = r ax+py=r ax+py=r的解 x 1 x_1 x1,接着可以得出 a x ≡ b ( m o d    p ) ax ≡ b (mod ~~p) axb(mod  p)的一组解为 x 0 = x 1 ∗ b / r x_0=x_1*b/r x0=x1b/r,设解之间的最小间隔为 s = p / r s=p/r s=p/r,且可以证明该方程组一共有 r r r个解

因此 a x ≡ b ( m o d    p ) ax ≡ b (mod ~~p) axb(mod  p)的最小整数解为 ( x 0 % s + s ) % s , a x ≡ b ( m o d    p ) (x_0\%s+s)\%s,ax ≡ b (mod ~~p) (x0%s+s)%s,axb(mod  p)的通解为 x = x 0 + k ∗ ( p / r )    ( k ∈ [ 0 , r − 1 ] ) x=x_0+k*(p/r) ~~(k∈[0,r-1]) x=x0+k(p/r)  (k[0,r1])

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1;y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return gcd;     //返回的是a,b的最大公因数
}

int solve(int a,int b,int p){
	int x,y,r,x0;
    r=exgcd(a,p,x,y);
    int s=p/r;
    x=x*b/r;
    x0=(x%s+s)%s; //最小整数解
    return x0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值