中国剩余定理

中国剩余定理

今有物不知其数,三三数之余二;五五数之余三;七七数之余二。问物几何?

答案:23

口诀:三人同行七十稀,五树梅花廿一枝,七子团圆月正半,除百零五便得知

其实原问题就是求解以下的同余方程组
{ x ≡ 2   ( m o d    3 ) x ≡ 3   ( m o d    5 ) x ≡ 2   ( m o d    7 ) \left\{ \begin{aligned} x \equiv 2 \, (mod \,\, 3) \\ x \equiv 3 \, (mod \,\, 5) \\ x \equiv 2 \, (mod \,\, 7) \end{aligned} \right. x2(mod3)x3(mod5)x2(mod7)
23 = ( 2 × 70 + 3 × 21 + 2 × 15 )    m o d    ( 3 × 5 ×   7 ) 23 = (2 \times 70 + 3 \times 21 + 2 \times 15) \,\, mod \,\,(3 \times 5 \times\ 7) 23=(2×70+3×21+2×15)mod(3×5× 7),那 70 , 21 , 15 70,21,15 702115是怎么求得的呢,通过以下三步:

  • 70 70 70实际上是 5 5 5 7 7 7的公倍数中模 3 3 3 1 1 1的最小的那个数, x ≡ 1   ( m o d    3 ) x \equiv 1 \,(mod\,\,3) x1(mod3),其中 x = 35 k x = 35k x=35k
  • 21 21 21实际上是 3 3 3 7 7 7的公倍数中模 5 5 5 1 1 1的最小的那个数, x ≡ 1   ( m o d    5 ) x \equiv 1\, (mod \,\,5) x1(mod5),其中 x = 21 k x = 21k x=21k
  • 15 15 15实际上是 3 3 3 5 5 5的公倍数中模 7 7 7 1 1 1的最小的那个数, x ≡ 1   ( m o d    7 ) x \equiv 1 \,(mod\,\,7) x1(mod7),其中 x = 15 k x = 15k x=15k

其中有什么原理呢?

首先假设 x 1 x_1 x1 x ≡ 2   ( m o d    3 ) x \equiv 2 \, (mod \,\, 3) x2(mod3)的解, x 2 x_2 x2 x ≡ 3   ( m o d    5 ) x \equiv 3 \, (mod \,\, 5) x3(mod5)的解, x 3 x_3 x3 x ≡ 2   ( m o d    7 ) x \equiv 2 \, (mod \,\, 7) x2(mod7)的解

那么能否进一步满足, x 1 + x 2 x_1+x_2 x1+x2 3 3 3 2 2 2也成立呢?只要满足** x 2 x_2 x2 3 3 3的倍数就可以,同理要使得 x 1 + x 3 x_1+x_3 x1+x3 3 3 3 2 2 2也成立,那么 x 3 x_3 x3也得是 3 3 3的倍数**,这是从 x 1 x_1 x1的角度出发

来看 x 2 x_2 x2 x 2 x_2 x2满足模 5 5 5 3 3 3成立。为了使得 x 1 + x 2 x_1+x_2 x1+x2也满足模 5 5 5 3 3 3成立,那么 x 1 x_1 x1必须是 5 5 5的倍数,同理, x 3 x_3 x3也要是 5 5 5的倍数,才能满足 x 2 + x 3 x_2+x_3 x2+x3 5 5 5 3 3 3成立。

最后是 x 3 x_3 x3。同理** x 1 , x 2 x_1,x_2 x1x2也必须是 7 7 7的倍数**。弄清楚了这些条件

那么 x 1 + x 2 + x 3 x_1+x_2+x_3 x1+x2+x3就是最终的一个答案了。总的来说这 3 3 3个数要满足

  • x 1 x_1 x1 3 3 3余数是 2 2 2,同时 x 1 x_1 x1 5 5 5 7 7 7的一个公倍数
  • x 2 x_2 x2 5 5 5余数是 3 3 3,同时 x 2 x_2 x2 3 3 3 7 7 7的一个公倍数
  • x 3 x_3 x3 7 7 7余数是 2 2 2,同时 x 3 x_3 x3 3 3 3 5 5 5的一个公倍数

需要注意的是, x 1 + x 2 + x 3 x_1+x_2+x_3 x1+x2+x3只是其中一个解,并不是最小的解。要明白如果 t t t是上述同余方程组的解那么 t + 105 k t+105k t+105k也是方程组的解。 105 105 105 3 , 5 , 7 3,5,7 357的最小公倍数

求解的时候,可以使用扩展欧几里德算法,将 x 1 x_1 x1 3 3 3余数是 2 2 2,变成 x 1 x_1 x1 3 3 3余数是 1 1 1,将答案乘以 2 2 2即可,相当于求 x 1 − 3 k = 1 x1 - 3k = 1 x13k=1

例题:

给定 n n n 组非负整数 a i , b i a_i, b_i ai,bi ,求解关于 x x x 的方程组的最小非负整数解。(其中 a i a_i ai两两互质)
{ x ≡ b 1   ( m o d    a 1 ) x ≡ b 2   ( m o d    a 2 ) . . . . . . . . . . . . . . . . x ≡ b n   ( m o d    a n ) \left\{ \begin{aligned} x \equiv b_1 \, (mod \,\, a_1) \\ x \equiv b_2 \, (mod \,\, a_2) \\ ................\\ x \equiv b_n \, (mod \,\, a_n) \end{aligned} \right. xb1(moda1)xb2(moda2)................xbn(modan)
输入

输入第一行包含整数 n n n

接下来 n n n 行,每行两个非负整数 a i , b i a_i, b_i ai,bi

输出

输出一行,为满足条件的最小非负整数 x x x

输入样例

3
2 1
3 2
5 3

输出样例

23

代码

#include <cstdio>
#include <iostream>
#define N 100005
#define ll long long
using namespace std;

ll a[N], b[N], M = 1;
int n;

void ex_gcd (ll a, ll b, ll &x, ll & y) { //扩展欧几里德
	if (!b) {
		x = 1, y = 0;
		return ;
	}
	ex_gcd(b, a%b, x, y);
	ll t = x;
	x = y;
	y = t - a / b * y;
}

ll CRT () {
	ll ans = 0, x, y, g;
	for (int i = 1; i <= n; i++)
		M *= a[i];
	for (int i = 1; i <= n; i++) {
		ex_gcd (M / a[i], a[i], x, y);
		ans = (ans + x * (M / a[i]) * b[i]) % M; 
	}
	return (ans + M) % M;
}

int main () {
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++) 
		scanf ("%lld %lld", &a[i], &b[i]);
	printf("%lld\n", CRT ());
	return 0;
}

你可能感兴趣的:(数学)