今有物不知其数,三三数之余二;五五数之余三;七七数之余二。问物几何?
答案: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. ⎩⎪⎨⎪⎧x≡2(mod3)x≡3(mod5)x≡2(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 70,21,15是怎么求得的呢,通过以下三步:
其中有什么原理呢?
首先假设 x 1 x_1 x1是 x ≡ 2 ( m o d 3 ) x \equiv 2 \, (mod \,\, 3) x≡2(mod3)的解, x 2 x_2 x2是 x ≡ 3 ( m o d 5 ) x \equiv 3 \, (mod \,\, 5) x≡3(mod5)的解, x 3 x_3 x3是 x ≡ 2 ( m o d 7 ) x \equiv 2 \, (mod \,\, 7) x≡2(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 x1,x2也必须是 7 7 7的倍数**。弄清楚了这些条件
那么 x 1 + x 2 + x 3 x_1+x_2+x_3 x1+x2+x3就是最终的一个答案了。总的来说这 3 3 3个数要满足
需要注意的是, 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 3,5,7的最小公倍数
求解的时候,可以使用扩展欧几里德算法,将 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 x1−3k=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. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧x≡b1(moda1)x≡b2(moda2)................x≡bn(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;
}