中国剩余定理:
m1, m2, m3, ... , mk 两两互质:(限制条件)
x = a1 (mod m1)
x = a2 (mod m2)
x = a3 (mod m3)
...
x = ak (mod mk)
若令 M = m1 * m2 * m3 * ... * mk
Mi = M / mi,Mi(-1) 表示 Mi 模 mi 的逆.
则有解 x = a1 * M1 * M1(-1) + a2 * M2 * M2(-1) + ... + ak * Mk * Mk(-1).其中Mi的逆元Mi(-1)可以用 Mi * x = 1 (mod mi) 来(扩展欧几里得解线性同余方程).
证明过程如下:(以下证明过程,m 和 a 弄反了,余数是m1, m2, 模数是 a1, a2).
x mod a1 = m1;
x mod a2 = m2;
即:
x = k1 * a1 + m1;
x = k2 * a2 + m2;
则:
k1 * a1 + m1 = k2 * a2 + m2;
即:
k1 * a1 - k2 * a2 = m2 - m1.
有解等价于: gcd (a1, a2) | m2 - m1;
exgcd求出k1, k2的值,则 x = k1 * a1 + m1 ;
有不定方程所有解:
k1 + k * (a2 / d), k2 + k * (a1 / d);
所以 x 的所有解: x = (k1 + k * (a2 /d )) * a1 + m1
x = a1 * k1 + m1 + k * (a1 * a2 / d)
x = (a1 * k1 + m1) + k * [a1, a2].
x = x0 + k * a.
代码实现:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL; // 2e9 的数据好像一般都用long long.
LL exgcd (LL a, LL b, LL & x, LL & y) {
if (!b) {
x = 1;
y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main () {
int n;
cin >> n;
LL a1, m1, a2, m2;
cin >> m1 >> a1;
LL x, k1, k2;
bool flag = 0;
for (int i = 2; i <= n; i ++ ) {
cin >> m2 >> a2;
int d = exgcd(m1, -m2, k1, k2); // m2 正负无所谓
if ((a2 - a1) % d) {
flag = 1;
break;
}
k1 *= (a2 - a1) / d;
int t = m2 / d;
k1 = (k1 % t + t) % t; // 数据范围卡的很紧,所以k1取最小整数解.
x = k1 * m1 + a1;
a1 = x;
m1 = abs(m1 / d * m2); // m1正数、负数均可以.
}
if(flag) cout << "-1" << endl;
else cout << (x % m1 + m1) % m1 << endl; // 答案要求最小整数解.
return 0;
}
THE END;