中国剩余定理与线性同余方程组求解
线性同余方程组的形式
实际上一元一次线性同余方程组,形式如下:
{
x
≡
r
0
(
m
o
d
m
0
)
x
≡
r
1
(
m
o
d
m
1
)
⋯
\begin{cases} x\equiv{r_0}({\rm{mod}}\,m_0) \\ x\equiv{r_1}({\rm{mod}}\,m_1) \\ \cdots \end{cases}
⎩⎪⎨⎪⎧x≡r0(modm0)x≡r1(modm1)⋯
包含有具体数字的线性同余方程组问题最早见于《孙子算经》(成书于约南北朝时期,因此与《孙子兵法》的孙子应该不是同一个孙子),该书也给出了该具体问题的解法。因此求解线性同余方程组有关的定理又称作孙子定理。但实际上《孙子算经》并未给出证明及一般性解法。最早的系统性论述应该是南宋时期秦九韶在《算术九章》中提出的“大衍求一术”。因此最后有关该问题的理论被称作中国剩余定理。
中国剩余定理
如果
m
0
,
m
1
,
⋯
m_0,m_1,\cdots
m0,m1,⋯两两互质,则方程有唯一解,在模
∏
i
m
i
\prod_{i}{m_i}
∏imi的意义下。解法如下:
令
M
=
∏
i
m
i
M=\prod_{i}{m_i}
M=∏imi,且
M
i
=
M
/
m
i
M_i=M/m_i
Mi=M/mi
对每一个
M
i
M_i
Mi求出在模
m
i
m_i
mi意义下的逆元,记作
x
i
x_i
xi
即满足
M
i
⋅
x
i
≡
1
(
m
o
d
m
i
)
M_i\cdot{x_i}\equiv1({\rm{mod}}\,m_i)
Mi⋅xi≡1(modmi)
则原方程组的解为
x
=
∏
i
r
i
⋅
x
i
⋅
M
i
m
o
d
M
x=\prod_{i}{r_i\cdot{x_i}\cdot{M_i}}\,\rm{mod}\,M
x=∏iri⋅xi⋅MimodM
#线性同余方程组的一般解法
使用中国剩余定理理论上可以很方便的解出模数两两互质的方程组。对于不互质的情况可以使用下面的一般解法。
##单独的线性同余方程求解
考虑单独的一个线性同余方程,已知
a
,
b
,
m
a,b,m
a,b,m,求
x
x
x满足如下方程:
a
x
≡
b
(
m
o
d
m
)
ax\equiv{b}({\rm{mod}}\,m)
ax≡b(modm)
原方程等价于:
a
x
+
m
y
=
b
ax+my=b
ax+my=b
根据裴蜀定理,上述方程有解的充要条件是
b
b
b是
g
c
d
(
a
,
m
)
gcd(a,m)
gcd(a,m)的整数倍。利用扩展的扩展的欧几里德算法可以很容易求得
x
0
x_0
x0使得:
a
x
0
+
m
y
0
=
g
c
d
(
a
,
m
)
ax_0+my_0=gcd(a,m)
ax0+my0=gcd(a,m)
于是很容易得到
x
x
x的一个特解为:
x
=
x
0
⋅
b
g
c
d
x=x_0\cdot\frac{b}{gcd}
x=x0⋅gcdb
显然
x
x
x有无穷多解,如果考虑在模
m
m
m的意义下,
x
x
x也有
g
c
d
gcd
gcd个不同的解,且成等差数列,公差为
m
/
g
c
d
m/gcd
m/gcd。因此很容易求得最小正整数解为:
x
=
x
0
⋅
b
g
c
d
m
o
d
m
g
c
d
x=x_0\cdot\frac{b}{gcd}\,\rm{mod}\,\frac{m}{gcd}
x=x0⋅gcdbmodgcdm
考虑方程
9
x
≡
6
(
m
o
d
12
)
9x\equiv6({\rm{mod}}\,12)
9x≡6(mod12)
根据扩展的欧几里德算法有:
9
x
0
+
12
y
0
=
3
9x_0+12y_0=3
9x0+12y0=3
得到
x
0
x_0
x0的一个解为11,所以
x
x
x的一个解为22,对4取模即可得到最小正整数解2,且在模12的意义下有3个解,分别是2、6、10。
##两个线性同余方程合并
考虑2个线性同余方程构成的方程组:
{
x
≡
r
0
(
m
o
d
m
0
)
x
≡
r
1
(
m
o
d
m
1
)
\begin{cases} x\equiv{r_0}({\rm{mod}}\,m_0) \\ x\equiv{r_1}({\rm{mod}}\,m_1) \end{cases}
{x≡r0(modm0)x≡r1(modm1)
分别等价于
{
x
=
r
0
+
m
0
z
0
x
=
r
1
+
m
1
z
1
\begin{cases} x=r_0+m_0z_0\\ x=r_1+m_1z_1 \end{cases}
{x=r0+m0z0x=r1+m1z1
因此有
m
0
z
0
=
m
1
z
1
+
r
1
−
r
0
m_0z_0=m_1z_1+r_1-r_0
m0z0=m1z1+r1−r0
两边对
m
2
m_2
m2取余数即可得到一个单独的关于
z
0
z_0
z0线性同余方程
m
0
z
0
≡
r
1
−
r
0
(
m
o
d
m
1
)
m_0z_0\equiv{r_1-r_0({\rm{mod}}\,m_1)}
m0z0≡r1−r0(modm1)
根据之前的结论,很容易判断是否有解并可以解出
z
0
z_0
z0。如果可解,可以得到一个方程:
x
≡
m
0
z
0
+
r
0
(
m
o
d
l
c
m
(
m
0
,
m
1
)
)
x\equiv{m_0z_0+r_0({\rm{mod}}\,lcm(m_0,m_1))}
x≡m0z0+r0(modlcm(m0,m1))
该方程与原方程组等价。其中
l
c
m
lcm
lcm为最小公倍数。
如此反复,就可以将线性同余方程组合并为一个方程,并且利用扩展的欧几里德算法求解。在每一步中,均需判断是否有解。
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;i<n;++i){
if ( !mergeCrt(r1,m1,remainder[i],mod[i],r1,m1) ){
return -1;
}
}
r1 %= m1;
if ( r1 < 0 ) r1 += m1;
return r1;
}
完整的程序可以见POJ2891