中国剩余定理
已知互质,方程 的最小正整数解,其中,,表示模的逆元,可通过求出
- 本质是求解同余方程组
- 如果直接按公式求解,结果可能会溢出,因此采用迭代的方式求解
- 考虑第1个和第2个方程,可得等式,变形得
- 令方程有解的充分必要条件是
- 此时,这里令,
- 若把看成,看成,则上式变成,即,相当于把两个同余方程合并成了一个
代码
typedef long long LL;
// 扩展欧几里得算法
int exgcd(int a, int b, int &x, int &y)
{
if (!b)
{
x = 1; y = 0;
return a;
}
int d = exgcd(b, a % b, y, x); // 递归结束时,y = x',x = y'
y -= (a/b) * x; // y = x'-(a / b) * y' = y - (a / b) * x
return d;
}
// 中国剩余定理
LL x = 0, m1, a1;
cin >> m1 >> a1;
for (int i = 0; i < n - 1; i ++ )
{
LL m2, a2;
cin >> m2 >> a2;
LL k1, k2;
LL d = exgcd(m1, -m2, k1, k2); // 求的不是最终解k1和k2
if ((a2 - a1) % d)
{
x = -1;
break; // 无解
}
k1 *= (a2 - a1) / d; // 变换成真正 的解
int t = m2 / d; // k1 = k1 + k * m2 / d
k1 = (k1 % t + t ) % t; // 变换成最小的正整数(防止C++对负数模取余)
x = k1 * m1 + a1;
// 把两个方程合并成一个方程
LL m = abs(m1 / d * m2); // 变成正数
a1 = k1 * m1 + a1;
m1 = m;
}
if (x != -1) x = (x % m1 + m1) % m1; // 变成最小正整数(防止C++对负数模取余)
cout << x << endl;