中国剩余定理
\quad 在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以 3 3 3余 2 2 2),五五数之剩三(除以 5 5 5余 3 3 3),七七数之 剩二(除以 7 7 7余 2 2 2),问物几何?”这个问题称为“孙子问题”,该问题的一般解法国际上称为“中国剩余定理”。
具体解法分三步:
- 找出三个数:从 3 3 3和 5 5 5的公倍数中找出被 7 7 7除余 1 1 1的最小数 15 15 15,从 3 3 3和 7 7 7的公倍数中找出被 5 5 5除余 1 1 1的最小数 21 21 21,最后从 5 5 5和 7 7 7的公倍数中找出除 3 3 3余 1 1 1的最小数 70 70 70。
- 用 15 15 15乘以 2 2 2( 2 2 2为最终结果除以 7 7 7的余数),用 21 21 21乘以 3 3 3( 3 3 3为最终结果除以 5 5 5的余数),同理,用 70 70 70乘以 2 2 2( 2 2 2为最终结果除以 3 3 3的余数),然后把三个乘积相加 15 ∗ 2 + 21 ∗ 3 + 70 ∗ 2 15∗2+21∗3+70∗2 15∗2+21∗3+70∗2得到和 233 233 233。
- 用 233 233 233除以 3 , 5 , 7 3,5,7 3,5,7三个数的最小公倍数 105 105 105,得到余数 23 23 23,即 233 233%105=23 233。这个余数 23 23 23就是符合条件的最小数。
\quad 就这么简单。我们在感叹神奇的同时不禁想知道古人是如何想到这个方法的,有什么基本的数学依据吗?
\quad 我们将“孙子问题”拆分成几个简单的小问题,从零开始,试图揣测古人是如何推导出这个解法的。
\quad 首先,我们假设 n 1 n_{1} n1是满足除以 3 3 3余 2 2 2的一个数,比如 2 , 5 , 8 2,5,8 2,5,8等等,也就是满足 3 ∗ k + 2 ( k > = 0 ) 3∗k+2(k>=0) 3∗k+2(k>=0)的一个任意数。同样,我们假设 n 2 n_{2} n2是满足除以 5 5 5余 3 3 3的一个数, n 3 n_{3} n3是满足除以 7 7 7余 2 2 2的一个数。
\quad 有了前面的假设,我们先从 n 1 n_{1} n1这个角度出发,已知 n 1 n_{1} n1满足除以 3 3 3余 2 2 2,能不能使得 n 1 + n 2 n_{1}+n_{2} n1+n2的和仍然满足除以 3 3 3余 2 2 2?进而使得 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和仍然满足除以 3 3 3余 2 2 2?
\quad 这就牵涉到一个最基本数学定理,如果有 a % b = c a\%b=c a%b=c,则有 ( a + k ∗ b ) % b = c (a+k∗b)\%b=c (a+k∗b)%b=c( k k k为非零整数),换句话说,如果一个除法运算的余数为 c c c,那么被除数与 k k k倍的除数相加(或相减)的和(差)再与除数相除,余数不变。这个是很好证明的。
\quad 以此定理为依据,如果 n 2 n_{2} n2是 3 3 3的倍数, n 1 + n 2 n_{1}+n_{2} n1+n2就依然满足除以 3 3 3余 2 2 2。同理,如果 n 3 n_{3} n3也是 3 3 3的倍数,那么 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和就满足除以 3 3 3余 2 2 2。这是从 n 1 n_{1} n1的角度考虑的,再从 n 2 , n 3 n_{2},n_{3} n2,n3的角度出发,我们可推导出以下三点:
- 为使 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和满足除以 3 3 3余 2 2 2, n 2 n_{2} n2和 n 3 n_{3} n3必须是 3 3 3的倍数。
- 为使 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和满足除以 5 5 5余 3 3 3, n 1 n_{1} n1和 n 3 n_{3} n3必须是 5 5 5的倍数。
- 为使 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和满足除以 7 7 7余 2 2 2, n 1 n_{1} n1和 n 2 n_{2} n2必须是 7 7 7的倍数。
\quad 因此,为使 n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3的和作为“孙子问题”的一个最终解,需满足:
- n 1 n_{1} n1除以 3 3 3余 2 2 2,且是 5 5 5和 7 7 7的公倍数。
- n 2 n_{2} n2除以 5 5 5余 3 3 3,且是 3 3 3和 5 5 5的公倍数。
- n 3 n_{3} n3除以 7 7 7余 2 2 2,且是 3 3 3和 5 5 5的公倍数。
\quad 所以,孙子问题解法的本质是从 5 5 5和 7 7 7的公倍数中找一个除以 3 3 3余 2 2 2的数 n 1 n_{1} n1,从 3 3 3和 7 7 7的公倍数中找一个除以 5 5 5余 3 3 3的数 n 2 n_{2} n2,从 3 3 3和 5 5 5的公倍数中找一个除以 7 7 7余 2 2 2的数 n 3 n_{3} n3,再将三个数相加得到解。在求 n 1 , n 2 , n 3 n_{1},n_{2},n_{3} n1,n2,n3时又用了一个小技巧,以 n 1 n_{1} n1为例,并非从 5 5 5和 7 7 7的公倍数中直接找一个除以 3 3 3余 2 2 2的数,而是先找一个除以 3 3 3余 1 1 1的数,再乘以 2 2 2。也就是先求出 5 5 5和 7 7 7的公倍数模 3 3 3下的逆元,再用逆元去乘余数。
\quad 最后,我们还要清楚一点, n 1 + n 2 + n 3 n_{1}+n_{2}+n_{3} n1+n2+n3只是问题的一个解,并不是最小的解。如何得到最小解?我们只需要从中最大限度的减掉掉 3 , 5 , 7 3,5,7 3,5,7的公倍数 105 105 105即可。道理就是前面讲过的定理“如果 a % b = c a\%b=c a%b=c,则有 ( a − k ∗ b ) % b = c ” (a−k∗b)\%b=c” (a−k∗b)%b=c”。所以 ( n 1 + n 2 + n 3 ) % 105 (n_{1}+n_{2}+n_{3})\%105 (n1+n2+n3)%105就是最终的最小解。
这样就得到了中国剩余定理的公式:
设正整数
m
1
,
m
2
,
,
,
,
,
m
k
m_{1},m_{2},,,,,m_{k}
m1,m2,,,,,mk两两互素,则同余方程组
那么再看提到的一元线性同余方程:(先做几个设定:设
N
i
N_{i}
Ni为能够被
m
1
,
m
2
,
.
.
.
.
.
.
,
m
i
−
1
,
m
i
+
1
,
.
.
.
.
.
m
k
m_{1}, m_{2},......, m_{i-1}, m_{i+1}, .....m_{k}
m1,m2,......,mi−1,mi+1,.....mk整除,但是除以
m
i
m_{i}
mi正好余1)
X = N 1 ∗ a 1 + N 2 ∗ a 2 + . . . . . . . + N n ∗ a n X = N_{1}*a_{1} + N_{2}*a_{2} + ....... + N_{n}*a_{n} X=N1∗a1+N2∗a2+.......+Nn∗an
就是我们要求的一个解,解集为 X % L C M ( m 1 , m 2 , . . . . , m n ) X \% LCM(m_{1}, m_{2}, ...., m_{n}) X%LCM(m1,m2,....,mn)。
剩下的问题就变成了如何求解$ N_{1}, N_{2} … N_{n}$,我们继续向下看:
假设 m = L C M ( m 1 , m 2 , . . . . , m n ) m = LCM(m_{1}, m_{2}, ...., m_{n}) m=LCM(m1,m2,....,mn) x ′ , y ′ x', y' x′,y′为任意整数。
因为 N i N_{i} Ni的性质, N i N_{i} Ni可以表示为: N i = = m / m i ∗ x ′ = = m i ∗ y ′ + 1 = = > m / m i ∗ x ′ + ( − m i ) ∗ y ′ = = 1. N_{i} == m / m_{i} * x' == m_{i} * y' + 1 ==> m / m_{i}* x' + (-m_{i}) * y' == 1. Ni==m/mi∗x′==mi∗y′+1==>m/mi∗x′+(−mi)∗y′==1.
推到现在有没有感觉很熟悉,对的!这个就是扩展欧几里德:
对于 g c d ( a , b ) = d gcd(a, b) = d gcd(a,b)=d, 存在 a ∗ x + b ∗ y = = g c d ( a , b ) a*x+b*y == gcd(a, b) a∗x+b∗y==gcd(a,b);
存在 g c d ( − m i , m / m i ) = = 1 gcd(-m_{i}, m/m_{i}) == 1 gcd(−mi,m/mi)==1,
对于 m / m i ∗ x ′ + ( − m i ) ∗ y ′ = = 1 , m/m_{i} * x' + (-m_{i}) * y' == 1, m/mi∗x′+(−mi)∗y′==1,
套用一下扩展欧几里德求出 x ′ , x', x′, 就可以求解出 N i N_{i} Ni。有了 N i N_{i} Ni求出 X X X就是分分钟的事情!
Code:
//中国剩余定理模板
ll china(int a[],int b[],int n)//a[]为除数,b[]为余数
{
int M=1,y,x=0;
for(int i=0; i<n; ++i) //算出它们累乘的结果
M*=a[i];
for(int i=0; i<n; ++i)
{
int w=M/a[i];
int tx=0;
int t=exgcd(w,a[i],tx,y);//计算逆元
x=(x+w*(b[i]/t)*x)%M;
}
return (x+M)%M;
}