扩展欧几里得定理(线性同余&&同余方程求解&&逆元)

  1. 线性同余

          线性同余方程(也可以叫模线性方程)是最基本的同余方程,即ax≡b (mod n)(   a≡b (mod n) 表示a和b模n同余,即a和b除以n的余数相等。即a%n = b%n),其中a、b、n都为常量,x是未知数,这个方程可以进行一定的转化,得到:ax = kn + b,这里的k为任意整数,于是我们可以得到更加一般的形式即:ax + by + c = 0,这个方程就是二维空间中的直线方程,但是x和y的取值为整数,所以这个方程的解是一些排列成直线的点集。

  2.    同余方程求解

          求解同余方程第一步是转化成一般式:ax + by = c,这个方程的求解步骤如下:

          i) 首先求出a和b的最大公约数d = gcd(a, b),那么原方程可以转化成d(ax/d + by/d) = c,容易知道(ax/d + by/d)为整数,如若d不能整除b,方程必然无解,算法结束;否则进入ii)。

          ii) 由i)可以得知,方程有解则一定可以表示成 ax + by = c = gcd(a, b)*c',那么我们先来看如何求解d = gcd(a, b) = ax + by,根据欧几里德定理,有:

          d = gcd(a, b) = gcd(b, a%b) = bx' + (a%b)y' = bx' + [a-b*(a/b)]y' = ay' + b[x' - (a/b)y']

          于是有x = y',  y = x' - (a/b)y'。

          由于gcd(a, b)是一个递归的计算,所以在求解(x, y)时,(x', y')其实已经利用递归计算出来了,递归出口为b == 0的时候(对比辗转相除,也是b == 0的时候递归结束),那么这时方程的解x0 = 1, y0 = 0。

    ll extend_gcd(ll a, ll b, ll &x, ll &y)
    {
        if (b == 0)
        {
            x = 1, y = 0;
            return a;
        }
        else
        {
            ll r = extend_gcd(b, a % b, y, x);
            y -= x * (a / b);
            return r;
        }
    }

    扩展欧几里德算法和欧几里德算法的返回值一致,都是gcd(a, b),传参多了两个未知数X, Y,采用引用的形式进行传递,对应上文提到的x, y,递归出口为b == 0,这时返回值为当前的a,因为gcd(a, 0) = a,(X, Y)初值为(1, 0),然后经过回溯不断计算新的(X, Y),这个计算是利用了之前的(X, Y)进行迭代计算的,直到回溯到最上层算法终止。最后得到的(X, Y)就是方程gcd(a, b) = ax + by的解。

          通过扩展欧几里德求的是ax + by = gcd(a, b)的解,令解为(x0, y0),代入原方程,得:ax0 + by0 = gcd(a, b),如果要求ax + by = c = gcd(a, b)*c',可以将上式代入,得:ax + by = c = (ax0 + by0)c',则x = x0c', y = y0c',这里的(x, y)只是这个方程的其中一组解,x的通解为 { x0c' + kb/gcd(a, b) | k为任意整数 },y的通解可以通过x通解的代入得出。

  3. 、逆元

          模逆元的最通俗含义可以效仿乘法,a*x = 1,则称x为a在乘法域上的逆(倒数);同样,如果ax≡1 (mod n),则称b为a模n的逆,简称逆元。求a模n的逆元,就是模线性方程ax≡b (mod n)中b等于1的特殊形式,可以用扩展欧几里德求解。并且在gcd(a, n) > 1时逆不存在。扩展欧几里得定理求逆元  a*x≡1(mod m) 等价于a*x+m*y=1 可以用扩展欧几里得求得一组解(x+m)mod m即为a的逆元。

    ll extend_gcd(ll a, ll b, ll &x, ll &y)
    {
        if (b == 0)
        {
            x = 1, y = 0;
            return a;
        }
        else
        {
            ll r = extend_gcd(b, a % b, y, x);
            y -= x * (a / b);
            return r;
        }
    }
    ll inv(ll a, ll n)
    {
        ll x, y;
        extend_gcd(a, n, x, y);
        x = (x % n + n) % n;
        return x;
    }

猜你喜欢

转载自blog.csdn.net/Alibaba_lhl/article/details/81066783