【算法】扩展欧几里得与同余方程

  很久之前写的……有很多错误。现在赶紧更新一波……

  1.扩展欧几里得算法:求解不定方程 (a * x + b * y = m)。

   首先,当 (m) 为 (gcd(a, b)) 的倍数时,方程有整数解;否则无整数解。

   证明:首先如果不满足此条件,一定不会有整数解。此处显然无须赘述。若 (p*x + q*y = gcd(p, q))  存在解,那么 (a*x + b*y = c) 存在解。因为可以将式子左右两边同除 (gcd(a, b)),那么此时有 (a_{1} * x + b_{1} * y = c_{1})。而此时 (gcd(a_{1}, b_{1}) = 1)。所以在求得了 (a_{1} * x + b_{1} * y = 1) 之后,我们可以同时给方程的两边乘上 (c _{1}) 。

     所以问题转化为:如何证明 (p * x + q * y = gcd(p, q)) 存在解?两边同除 (gcd(p, q)) 得到 (a * x + b * y = 1)((gcd(a, b) = 1))。

根据欧几里得算法我们有 (gcdleft ( a,b ight ) = gcdleft ( b,a mod  b ight ))

我们若能求出 (b * x' + left ( a mod b ight ) * y' = gcd(a, b)),

则:(b * x' + left ( a mod b ight ) * y')

( = a * y' + b * left ( x' - left ( frac{a}{b} ight )* y' ight ))

(=gcdleft ( a,b ight ));

又因为(gcd(a, b) = 1),

所以得出:(x = y', y = x' - left ( frac{a}{b} ight )* y');

   在代码实现上可以递归求解:

void exgcd(int a, int b, int &x, int &y)
{
    if(!b) { x = 1, y = 0; return; }
    exgcd(b, a % b, x, y);
    ll tem = x;
    x = y;
    y = tem - a / b * y;
}

    在我们获得了不定方程的一组解(left ( x_{0},y_{0} ight ))之后,则不定方程的任何一组解满足 :(Delta x = frac{m * b}{gcdleft ( a,b ight )}, Delta y = frac{m * a}{gcdleft ( a,b ight )})。

    扩展欧几里得算法一个非常常见的应用即为:求乘法逆元。

  2.同余方程:

    求解形如 (a * xequiv b left ( mod m ight ) ) 的方程。其实我并不是很会同余方程,但有两个定理还是非常重要的:

若(gcdleft ( a,b ight )=1),则方程(axequiv c left ( mod b ight )) 在 (left [ 0, b - 1 ight ])上有唯一解。

若(gcdleft ( a,b ight )=d, d|c),则方程(axequiv c left ( mod b ight )) 在 (left [ 0, frac{b}{d} - 1 ight ])上有唯一解。

    之前我是不会证明的,现在会了,感谢我Daddy的大力相助。在这里就截一下图(公式写起来好麻烦呀……)

    

    这两条性质让我们知道在求解模意义下的问题时(尤其是在卷积和反演中需要反复变化枚举对象时),可以转化为枚举模后的结果。例如(nx equiv  k left ( mod m ight )),(k in left [ 0, m - 1 ight ])。则当(x in left [ 0, q ight]) 时,(nx mod m = k)  一共出现了(frac{q}{frac{m}{d}}) 次。

原文地址:https://www.cnblogs.com/twilight-sx/p/9158413.html