「物不知数」问题:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
即求满足以下条件的整数:除以 3 3 3 余 2 2 2 ,除以 5 5 5 余 3 3 3 ,除以 7 7 7 余 2 2 2 。
该问题最早见于《孙子算经》中,并有该问题的具体解法。宋朝数学家秦九韶于 1247 年《数书九章》卷一、二《大衍类》对「物不知数」问题做出了完整系统的解答。上面具体问题的解答口诀由明朝数学家程大位在《算法统宗》中给出:
三人同行七十希,五树梅花廿一支,七子团圆正半月,除百零五便得知。
2 × 70 + 3 × 21 + 2 × 15 = 233 = 2 × 105 + 23 2\times 70+3\times 21+2\times 15=233=2\times 105+23 2 × 70 + 3 × 21 + 2 × 15 = 233 = 2 × 105 + 23 ,故答案为 23 23 23 。
中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 n 1 , n 2 , ⋯ , n k n_1, n_2, \cdots, n_k n 1 , n 2 , ⋯ , n k 两两互质):
{ x ≡ a 1 ( m o d n 1 ) x ≡ a 2 ( m o d n 2 ) ⋮ x ≡ a k ( m o d n k ) \begin{cases}
x &\equiv a_1 \pmod {n_1} \\
x &\equiv a_2 \pmod {n_2} \\
&\vdots \\
x &\equiv a_k \pmod {n_k} \\
\end{cases} ⎩ ⎨ ⎧ x x x ≡ a 1 ( mod n 1 ) ≡ a 2 ( mod n 2 ) ⋮ ≡ a k ( mod n k )
上面的「物不知数」问题就是一元线性同余方程组的一个实例。
计算所有模数的积 n n n ;
对于第 i i i 个方程:
计算 m i = n n i m_i=\frac{n}{n_i} m i = n i n ;
计算 m i m_i m i 在模 n i n_i n i 意义下的 逆元 m i − 1 m_i^{-1} m i − 1 ;
计算 c i = m i m i − 1 c_i=m_im_i^{-1} c i = m i m i − 1 (不要对 n i n_i n i 取模 )。
方程组在模 n n n 意义下的唯一解为:x = ∑ i = 1 k a i c i ( m o d n ) x=\sum_{i=1}^k a_ic_i \pmod n x = ∑ i = 1 k a i c i ( mod n ) 。
LL CRT ( int k , LL * a , LL * r ) {
LL n = 1 , ans = 0 ;
for ( int i = 1 ; i <= k; i ++ ) n = n * r[i];
for ( int i = 1 ; i <= k; i ++ ) {
LL m = n / r[i], b, y;
exgcd (m, r[i], b, y); // b * m mod r[i] = 1
ans = (ans + a[i] * m * b % n) % n;
}
return (ans % n + n) % n;
}
我们需要证明上面算法计算所得的 x x x 对于任意 i = 1 , 2 , ⋯ , k i=1,2,\cdots,k i = 1 , 2 , ⋯ , k 满足 x ≡ a i ( m o d n i ) x\equiv a_i \pmod {n_i} x ≡ a i ( mod n i ) 。
当 i ≠ j i\neq j i = j 时,有 m j ≡ 0 ( m o d n i ) m_j \equiv 0 \pmod {n_i} m j ≡ 0 ( mod n i ) ,故 c j ≡ m j ≡ 0 ( m o d n i ) c_j \equiv m_j \equiv 0 \pmod {n_i} c j ≡ m j ≡ 0 ( mod n i ) 。又有 c i ≡ m i ⋅ ( m i − 1 m o d n i ) ≡ 1 ( m o d n i ) c_i \equiv m_i \cdot (m_i^{-1} \bmod {n_i}) \equiv 1 \pmod {n_i} c i ≡ m i ⋅ ( m i − 1 mod n i ) ≡ 1 ( mod n i ) ,所以我们有:
x ≡ ∑ j = 1 k a j c j ( m o d n i ) ≡ a i c i ( m o d n i ) ≡ a i ⋅ m i ⋅ ( m i − 1 m o d n i ) ( m o d n i ) ≡ a i ( m o d n i ) \begin{aligned}
x&\equiv \sum_{j=1}^k a_jc_j &\pmod {n_i} \\
&\equiv a_ic_i &\pmod {n_i} \\
&\equiv a_i \cdot m_i \cdot (m^{-1}_i \bmod n_i) &\pmod {n_i} \\
&\equiv a_i &\pmod {n_i}
\end{aligned} x ≡ j = 1 ∑ k a j c j ≡ a i c i ≡ a i ⋅ m i ⋅ ( m i − 1 mod n i ) ≡ a i ( mod n i ) ( mod n i ) ( mod n i ) ( mod n i )
即对于任意 i = 1 , 2 , ⋯ , k i=1,2,\cdots,k i = 1 , 2 , ⋯ , k ,上面算法得到的 x x x 总是满足 x ≡ a i ( m o d n i ) x\equiv a_i \pmod{n_i} x ≡ a i ( mod n i ) ,即证明了解同余方程组的算法的正确性。
因为我们没有对输入的 a i a_i a i 作特殊限制,所以任何一组输入 { a i } \{a_i\} { a i } 都对应一个解 x x x 。
另外,若 x ≠ y x\neq y x = y ,则总存在 i i i 使得 x x x 和 y y y 在模 n i n_i n i 下不同余。
故系数列表 { a i } \{a_i\} { a i } 与解 x x x 之间是一一映射关系,方程组总是有唯一解。
下面演示 CRT 如何解「物不知数」问题。
n = 3 × 5 × 7 = 105 n=3\times 5\times 7=105 n = 3 × 5 × 7 = 105 ;
三人同行 七十 希:n 1 = 3 , m 1 = n / n 1 = 35 , m 1 − 1 ≡ 2 ( m o d 3 ) n_1=3, m_1=n/n_1=35, m_1^{-1}\equiv 2\pmod 3 n 1 = 3 , m 1 = n / n 1 = 35 , m 1 − 1 ≡ 2 ( mod 3 ) ,故 c 1 = 35 × 2 = 70 c_1=35\times 2=70 c 1 = 35 × 2 = 70 ;
五树梅花 廿一 支:n 2 = 5 , m 2 = n / n 2 = 21 , m 2 − 1 ≡ 1 ( m o d 5 ) n_2=5, m_2=n/n_2=21, m_2^{-1}\equiv 1\pmod 5 n 2 = 5 , m 2 = n / n 2 = 21 , m 2 − 1 ≡ 1 ( mod 5 ) ,故 c 2 = 21 × 1 = 21 c_2=21\times 1=21 c 2 = 21 × 1 = 21 ;
七子团圆正 半月 :n 3 = 7 , m 3 = n / n 3 = 15 , m 3 − 1 ≡ 1 ( m o d 7 ) n_3=7, m_3=n/n_3=15, m_3^{-1}\equiv 1\pmod 7 n 3 = 7 , m 3 = n / n 3 = 15 , m 3 − 1 ≡ 1 ( mod 7 ) ,故 c 3 = 15 × 1 = 15 c_3=15\times 1=15 c 3 = 15 × 1 = 15 ;
所以方程组的唯一解为 x ≡ 2 × 70 + 3 × 21 + 2 × 15 ≡ 233 ≡ 23 ( m o d 105 ) x\equiv 2\times 70+3\times 21+2\times 15\equiv 233\equiv 23 \pmod {105} x ≡ 2 × 70 + 3 × 21 + 2 × 15 ≡ 233 ≡ 23 ( mod 105 ) 。(除 百零五 便得知)