中国剩余定理 引入 「物不知数」问题:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?
即求满足以下条件的整数:除以 3 余 2 ,除以 5 余 3 ,除以 7 余 2 。
该问题最早见于《孙子算经》中,并有该问题的具体解法。宋朝数学家秦九韶于 1247 年《数书九章》卷一、二《大衍类》对「物不知数」问题做出了完整系统的解答。上面具体问题的解答口诀由明朝数学家程大位在《算法统宗》中给出:
三人同行七十希,五树梅花廿一支,七子团圆正半月,除百零五便得知。
2 × 70 + 3 × 21 + 2 × 15 = 233 = 2 × 105 + 23 ,故答案为 23 。
定义 中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 n 1 , n 2 , ⋯ , n k 两两互质):
{ x ≡ a 1 ( mod n 1 ) x ≡ a 2 ( mod n 2 ) ⋮ x ≡ a k ( mod n k ) 上面的「物不知数」问题就是一元线性同余方程组的一个实例。
过程 计算所有模数的积 n ; 对于第 i 个方程:计算 m i = n n i ; 计算 m i 在模 n i 意义下的 逆元 m i − 1 ; 计算 c i = m i m i − 1 (不要对 n i 取模 )。 方程组在模 n 意义下的唯一解为:x = ∑ i = 1 k a i c i ( mod n ) 。 实现 C++ Python
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 ;
}
def CRT ( k , a , r ):
n = 1
ans = 0
for i in range ( 1 , k + 1 ):
n = n * r [ i ]
for i in range ( 1 , k + 1 ):
m = n // r [ i ]
b = y = 0
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 对于任意 i = 1 , 2 , ⋯ , k 满足 x ≡ a i ( mod n i ) 。
当 i ≠ j 时,有 m j ≡ 0 ( mod n i ) ,故 c j ≡ m j ≡ 0 ( mod n i ) 。又有 c i ≡ m i ⋅ ( m i − 1 mod n i ) ≡ 1 ( mod n i ) ,所以我们有:
x ≡ ∑ j = 1 k a j c j ( mod n i ) ≡ a i c i ( mod n i ) ≡ a i ⋅ m i ⋅ ( m i − 1 mod n i ) ( mod n i ) ≡ a i ( mod n i ) 即对于任意 i = 1 , 2 , ⋯ , k ,上面算法得到的 x 总是满足 x ≡ a i ( mod n i ) ,即证明了解同余方程组的算法的正确性。
因为我们没有对输入的 a i 作特殊限制,所以任何一组输入 { a i } 都对应一个解 x 。
另外,若 x ≠ y ,则总存在 i 使得 x 和 y 在模 n i 下不同余。
故系数列表 { a i } 与解 x 之间是一一映射关系,方程组总是有唯一解。
解释 下面演示 CRT 如何解「物不知数」问题。
n = 3 × 5 × 7 = 105 ;三人同行 七十 希:n 1 = 3 , m 1 = n / n 1 = 35 , m 1 − 1 ≡ 2 ( mod 3 ) ,故 c 1 = 35 × 2 = 70 ; 五树梅花 廿一 支:n 2 = 5 , m 2 = n / n 2 = 21 , m 2 − 1 ≡ 1 ( mod 5 ) ,故 c 2 = 21 × 1 = 21 ; 七子团圆正 半月 :n 3 = 7 , m 3 = n / n 3 = 15 , m 3 − 1 ≡ 1 ( mod 7 ) ,故 c 3 = 15 × 1 = 15 ; 所以方程组的唯一解为 x ≡ 2 × 70 + 3 × 21 + 2 × 15 ≡ 233 ≡ 23 ( mod 105 ) 。(除 百零五 便得知) Garner 算法 CRT 的另一个用途是用一组比较小的质数表示一个大的整数。
例如,若 a 满足如下线性方程组,且 a < ∏ i = 1 k p i (其中 p i 为质数):
{ a ≡ a 1 ( mod p 1 ) a ≡ a 2 ( mod p 2 ) ⋮ a ≡ a k ( mod p k ) 我们可以用以下形式的式子(称作 a 的混合基数表示)表示 a :
a = x 1 + x 2 p 1 + x 3 p 1 p 2 + … + x k p 1 … p k − 1 Garner 算法 将用来计算系数 x 1 , … , x k 。
令 r i j 为 p i 在模 p j 意义下的 逆 :
p i ⋅ r i , j ≡ 1 ( mod p j ) 把 a 代入我们得到的第一个方程:
a 1 ≡ x 1 ( mod p 1 ) 代入第二个方程得出:
a 2 ≡ x 1 + x 2 p 1 ( mod p 2 ) 方程两边减 x 1 ,除 p 1 后得
a 2 − x 1 ≡ x 2 p 1 ( mod p 2 ) ( a 2 − x 1 ) r 1 , 2 ≡ x 2 ( mod p 2 ) x 2 ≡ ( a 2 − x 1 ) r 1 , 2 ( mod p 2 ) 类似地,我们可以得到:
x k = ( … ( ( a k − x 1 ) r 1 , k − x 2 ) r 2 , k ) − … ) r k − 1 , k mod p k 实现 该算法的时间复杂度为 O ( k 2 ) 。实际上 Garner 算法并不要求模数为质数,只要求模数两两互质,我们有如下伪代码:
Chinese Remainder Algorithm cra ( v , m ) : Input : m = ( m 0 , m 1 , … , m n − 1 ) , m i ∈ Z + ∧ gcd ( m i , m j ) = 1 for all i ≠ j , v = ( v 0 , … , v n − 1 ) where v i = x mod m i . Output : x mod ∏ i = 0 n − 1 m i . 1 for i from 1 to ( n − 1 ) do 2 C i ← ( ∏ j = 0 i − 1 m j ) − 1 mod m i 3 x ← v 0 4 for i from 1 to ( n − 1 ) do 5 u ← ( v i − x ) ⋅ C i mod m i 6 x ← x + u ∏ j = 0 i − 1 m j 7 return ( x ) 可以发现在第六行中的计算过程对应上述混合基数的表示。
应用 某些计数问题或数论问题出于加长代码、增加难度、或者是一些其他原因,给出的模数:不是质数 !
但是对其质因数分解会发现它没有平方因子,也就是该模数是由一些不重复的质数相乘得到。
那么我们可以分别对这些模数进行计算,最后用 CRT 合并答案。
下面这道题就是一个不错的例子。
洛谷 P2480 [SDOI2010] 古代猪文 给出 G , n (1 ≤ G , n ≤ 10 9 ),求:
G ∑ k ∣ n ( n k ) mod 999 911 659 首先,当 G = 999 911 659 时,所求显然为 0 。
否则,根据 欧拉定理 ,可知所求为:
G ∑ k ∣ n ( n k ) mod 999 911 658 mod 999 911 659 现在考虑如何计算:
∑ k ∣ n ( n k ) mod 999 911 658 因为 999 911 658 不是质数,无法保证 ∀ x ∈ [ 1 , 999 911 657 ] ,x 都有逆元存在,上面这个式子我们无法直接计算。
注意到 999 911 658 = 2 × 3 × 4679 × 35617 ,其中每个质因子的最高次数均为一,我们可以考虑分别求出 ∑ k ∣ n ( n k ) 在模 2 ,3 ,4679 ,35617 这几个质数下的结果,最后用中国剩余定理来合并答案。
也就是说,我们实际上要求下面一个线性方程组的解:
{ x ≡ a 1 ( mod 2 ) x ≡ a 2 ( mod 3 ) x ≡ a 3 ( mod 4679 ) x ≡ a 4 ( mod 35617 ) 而计算一个组合数对较小的质数取模后的结果,可以利用 卢卡斯定理 。
扩展:模数不互质的情况 两个方程 设两个方程分别是 x ≡ a 1 ( mod m 1 ) 、x ≡ a 2 ( mod m 2 ) ;
将它们转化为不定方程:x = m 1 p + a 1 = m 2 q + a 2 ,其中 p , q 是整数,则有 m 1 p − m 2 q = a 2 − a 1 。
由 裴蜀定理 ,当 a 2 − a 1 不能被 gcd ( m 1 , m 2 ) 整除时,无解;
其他情况下,可以通过 扩展欧几里得算法 解出来一组可行解 ( p , q ) ;
则原来的两方程组成的模方程组的解为 x ≡ b ( mod M ) ,其中 b = m 1 p + a 1 ,M = lcm ( m 1 , m 2 ) 。
多个方程 用上面的方法两两合并即可。
习题 本页面最近更新:2024/5/8 20:33:33 ,更新历史 发现错误?想一起完善? 在 GitHub 上编辑此页! 本页面贡献者:StudyingFather , Chrogeek , iamtwz , 383494 , ChungZH , countercurrent-time , Early0v0 , Enter-tainer , Great-designer , H-J-Granger , Haohu Shen , Henry-ZHR , hly1204 , ImpleLee , Ir1d , kzoacn , little-cindy , MegaOwIer , Menci , NachtgeistW , namasikanam , ouuan , Phemon , renbaoshuo , shawlleyw , sshwy , stevebraveman , SukkaW , Tiphereth-A , Unnamed2964 , Xeonacid , xyf007 , Yanjun-Zhao 本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用