AcWing 204 题解(中国剩余定理)
传送门
题面:
给你两个长度为\(n\)的数组\(a,m\),要求你找到一个数字\(x\)满足对于每一个\(i (1 \leq i \leq n)\),都有\(x ≡ m_i (\mod a_i)\)
把\(x\)输出。
思路(推导过程):
首先我们看一下第一个式子和第二个式子
\(x \mod a_1 = m_1, x \mod a_2 = m_2\)
得到:\(x = k_1\times a_1 + m_1 = k_2\times a_2 + m_2\)
得到:\(k_1\times a_1 - k_2\times a_2 = m_2 - m_1\)
那么如果\((m_2-m_1)\mod \gcd(a_1, a_2) \neq 0\)说明无解,否则(跨过大金字)继续往下
我们用扩展欧几里得算法做\(a_1,a_2\)时,会计算出两个数,就是\(k_1,k_2\)
然后\(x = (k_1 + k \times a_2 ÷ d) \times a_1 + m_1\)(\(k\)是某一个数字)
那么\(x = k_1 \times a_1 + m_1 + k \times a_1 \times a_2 ÷ d\)
接下来跨过大金字
那么也就等于 \(x = k_1 \times a_1 + m_1 + k \times lcm(a_1,a_2)\)
我们把\(k_1 \times a_1\) 记为 \(x_0\),把 \(lcm(a_1,a_2)\) 记为 \(a\)
那么\(x = x_0 + k \times a\)
上述是合并两个式子,其实合并\(n\)个式子也同理,无非就是多合并几次嘛
总的来说,最后的形式也是\(x =x_0+k \times a\)
那么\(x \mod a ≡ x_0\)
那么要求的就是\(x_0 \mod a\) 的正余数
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int exgcd(int a, int b, int& x, int& y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
int x1, y1;
int d = exgcd(b, a % b, x1, y1);
x = y1;
y = x1 - a / b * y1;
return d;
}
signed main()
{
int n;
cin >> n;
int a1, m1;
cin >> a1 >> m1;
bool flag = false;
for (int i = 2; i <= n; i++)
{
int a2, m2;
cin >> a2 >> m2;
int k1, k2;
int d = exgcd(a1, a2, k1, k2);
if ((m1 - m2) % d != 0) // 无解
{
flag = true;
}
// 下面可以直接按照推导公式去做。
k1 *= ((m2 - m1) / d);
int t = (a2 / d);
k1 = (k1 % t + t) % t; // 注意直接模可能会导致负数,要模完之后再加模数在模一次。
m1 += a1 * k1;
a1 = abs(a1 / d * a2);
}
if (flag) cout << -1 << endl; // 无解输出-1
else cout <<(m1 % a1 + a1) % a1 << endl; // 注意直接模可能会导致负数,要模完之后再加模数在模一次。
return 0;
}

浙公网安备 33010602011771号