中国剩余定理与线性同余方程组求解

  • 线性同余方程组的形式
  • 中国剩余定理
  • 线性同余方程组的一般解法
    • 单独的线性同余方程求解
    • 两个线性同余方程合并

线性同余方程组的形式

实际上一元一次线性同余方程组,形式如下:

xr0(modm0)xr1(modm1) { x ≡ r 0 ( m o d m 0 ) x ≡ r 1 ( m o d m 1 ) ⋯

包含有具体数字的线性同余方程组问题最早见于《孙子算经》(成书于约南北朝时期,因此与《孙子兵法》的孙子应该不是同一个孙子),该书也给出了该具体问题的解法。因此求解线性同余方程组有关的定理又称作孙子定理。但实际上《孙子算经》并未给出证明及一般性解法。最早的系统性论述应该是南宋时期秦九韶在《算术九章》中提出的“大衍求一术”。因此最后有关该问题的理论被称作中国剩余定理。

中国剩余定理

如果 m0,m1, m 0 , m 1 , ⋯ 两两互质,则方程有唯一解,在模 imi ∏ i m i 的意义下。解法如下:
M=imi M = ∏ i m i ,且 Mi=M/mi M i = M / m i
对每一个 Mi M i 求出在模 mi m i 意义下的逆元,记作 xi x i
即满足 Mixi1(modmi) M i ⋅ x i ≡ 1 ( m o d m i )
则原方程组的解为 x=irixiMimodM x = ∏ i r i ⋅ x i ⋅ M i m o d M

线性同余方程组的一般解法

使用中国剩余定理理论上可以很方便的解出模数两两互质的方程组。对于不互质的情况可以使用下面的一般解法。

单独的线性同余方程求解

考虑单独的一个线性同余方程,已知 a,b,m a , b , m ,求 x x 满足如下方程:

axb(modm) a x ≡ b ( m o d m )

原方程等价于:
ax+my=b a x + m y = b

根据裴蜀定理,上述方程有解的充要条件是 b b gcd(a,m) g c d ( a , m ) 的整数倍。利用扩展的 扩展的欧几里德算法可以很容易求得 x0 x 0 使得:
ax0+my0=gcd(a,m) a x 0 + m y 0 = g c d ( a , m )

于是很容易得到 x x 的一个特解为:
x=x0bgcd x = x 0 ⋅ b g c d

显然 x x 有无穷多解,如果考虑在模 m m 的意义下, x x 也有 gcd g c d 个不同的解,且成等差数列,公差为 m/gcd m / g c d 。因此很容易求得最小正整数解为:
x=x0bgcdmodmgcd x = x 0 ⋅ b g c d m o d m g c d

考虑方程
9x6(mod12) 9 x ≡ 6 ( m o d 12 )

根据扩展的欧几里德算法有:
9x0+12y0=3 9 x 0 + 12 y 0 = 3

得到 x0 x 0 的一个解为11,所以 x x 的一个解为22,对4取模即可得到最小正整数解2,且在模12的意义下有3个解,分别是2、6、10。

两个线性同余方程合并

考虑2个线性同余方程构成的方程组:

{xr0(modm0)xr1(modm1) { x ≡ r 0 ( m o d m 0 ) x ≡ r 1 ( m o d m 1 )

分别等价于
{x=r0+m0z0x=r1+m1z1 { x = r 0 + m 0 z 0 x = r 1 + m 1 z 1

因此有
m0z0=m1z1+r1r0 m 0 z 0 = m 1 z 1 + r 1 − r 0

两边对 m2 m 2 取余数即可得到一个单独的关于 z0 z 0 线性同余方程
m0z0r1r0(modm1) m 0 z 0 ≡ r 1 − r 0 ( m o d m 1 )

根据之前的结论,很容易判断是否有解并可以解出 z0 z 0 。如果可解,可以得到一个方程:
xm0z0+r0(modlcm(m0,m1)) x ≡ m 0 z 0 + r 0 ( m o d l c m ( m 0 , m 1 ) )

该方程与原方程组等价。其中 lcm l c m 为最小公倍数。
如此反复,就可以将线性同余方程组合并为一个方程,并且利用扩展的欧几里德算法求解。在每一步中,均需判断是否有解。

typedef long long int llt;
//to convert two congruence equations to equivalent one
//x = r1 (mod m1)
//x = r2 (mod m2)
//the out put is:  x = r3 (mod m3)
//return true if there is a solution, otherwise false
bool mergeCrt(llt r1,llt m1,llt r2,llt m2,llt&r3,llt&m3){
    llt x,y;
    llt g = exEuclid(m1,m2,x,y);
    llt r = (r2 - r1) % m2;
    if ( r < 0 ) r += m2;

    if ( r % g ) return false;//no solution

    x = r / g * x % ( m2 / g );//the least positive solution

    m3 = m1 / g * m2; //lcm
    r3 = ( ( x * m1 ) % m3 + r1 ) % m3;
    return true;
}

//Chinese remainder theorem to solve linear congruence equations
//n is the count of equations
//remainder is the array of remainders, index from 0
//mod is the array of modules, index from 0
//return the least positive solution or -1 if there is no solution
llt Crt(int n,llt const remainder[],llt const mod[]){
    llt r1 = remainder[0],m1 = mod[0];
    for(int i=1;iif ( !mergeCrt(r1,m1,remainder[i],mod[i],r1,m1) ){
            return -1;
        }
    }

    r1 %= m1;
    if ( r1 < 0 ) r1 += m1;
    return r1;
}

完整的程序可以见POJ2891

你可能感兴趣的:(ACM数论,ACM/ICPC)