本文讨论线性同余方程的求解。

基本概念

为整数, 为未知数,那么,形如

的方程称为 线性同余方程(linear congruence equation)。

求解线性同余方程,需要找到区间 的全部解。当然,将它们加减 的任意倍数,依然是方程的解。在模 的意义下,这些就是该方程的全部解。

本文接下来介绍了两种求解线性同余方程的思路,分别利用了逆元和不定方程。对于一般的情形,逆元和不定方程的求解都需要用到 扩展欧几里得算法,因此,这两种思路其实是一致的。

用逆元求解

首先,考虑 互素的情形,即 的情形。此时,可以计算 逆元 ,并将方程两边同乘以 ,这就得到方程的唯一解:

紧接着,考虑 不互素的情形,即 的情形。此时,原方程不一定有解。例如, 就没有解。因此,需要考虑两种情形:

  • 不能整除 时,方程无解。对于任意的 ,方程左侧 都是 的倍数,但是方程右侧 不是 的倍数。因此,它们不可能相差 的倍数,因为 的倍数也一定是 的倍数。因此,方程无解。

  • 可以整除 时,可以将方程的参数 都同除以 ,得到一个新的方程:

    其中,,也就是说, 互素。这种情形已经在前文解决,所以,可以通过求解逆元得到方程的一个解 .

    显然, 也是原方程的一个解。但这并非原方程唯一的解。由于转化后的方程的全体解为

    这些解中落在区间 的那些,就是原方程在区间 中的全部解:

总结这两种情形,线性同余方程的 解的数量 等于

用不定方程求解

线性同余方程等价于关于 二元一次不定方程

利用所引页面的讨论,方程有解当且仅当 ,而且该方程的一组通解是

其中, 是它们的最大公约数, 是任意整数。

进而,线性同余方程的通解就是

取模就得到同余方程的最小(非负)整数解,也就是上文的 .

参考实现

本节提供的参考实现可以得到同余方程的最小非负整数解。如果解不存在,则输出

参考实现

[list2tab]

  • C++

    // Extended Euclidean Algorithm.
    // Finds integers x, y such that a*x + b*y = gcd(a, b),
    // and returns gcd(a, b).
    int ex_gcd(int a, int b, int& x, int& y) {
      if (!b) {
        x = 1;
        y = 0;
        return a;
      } else {
        int d = ex_gcd(b, a % b, y, x);
        y -= a / b * x;
        return d;
      }
    }
     
    // Solves the linear congruence equation:
    //     a * x ≡ b (mod n), where n > 0.
    // Returns the smallest non-negative solution x,
    // or -1 if there is no solution.
    int solve_linear_congruence_equation(int a, int b, int n) {
      int x, y;
      int d = ex_gcd(a, n, x, y);
      if (b % d) return -1;
      n /= d;
      return ((long long)x * (b / d) % n + n) % n;
    }
  • Python

    def ex_gcd(a, b):
        """
        Extended Euclidean Algorithm.
        Finds integers x, y such that a*x + b*y = gcd(a, b),
        and returns (gcd, x, y).
        """
        if b == 0:
            return a, 1, 0
        d, x1, y1 = ex_gcd(b, a % b)
        x = y1
        y = x1 - (a // b) * y1
        return d, x, y
     
     
    def solve_linear_congruence_equation(a, b, n):
        """
        Solves the linear congruence equation:
            a * x ≡ b (mod n), where n > 0.
        Returns the smallest non-negative solution x,
        or -1 if there is no solution.
        """
        d, x, y = ex_gcd(a, n)
        if b % d != 0:
            return -1
        n //= d
        return (x * (b // d) % n + n) % n

习题

本页面主要译自博文 Модульное линейное уравнение первого порядка 与其英文翻译版 Linear Congruence Equation。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。内容有改动。