中国剩余定理
一组线性同余方程组
形如:\(\begin{array}{l} \left\{\begin{matrix} x \equiv a_1\ (\ mod\ m_1) \\ x \equiv a_2\ (\ mod\ m_2) \\ ...\\ ...\\ x \equiv a_n\ (\ mod\ m_n) \end{matrix}\right. \end{array}\)
\(CRT\)
1、条件:方程组中的 \(m_1,m_2,...,m_n\) 两两互质,现在我们令 \(M=m_1·m_2·...·m_n\),我们再令 \(M_i=M/m_i\),定义 \(t_i\) 为每个 \(M_i\) 模上 \(m_i\) 下的逆元,即满足 \(M_i·t_i\equiv 1\ (\ mod\ m_i)\),那么我们就可以构造出一组解 \(x_0=\sum_{i=1}^{n}a_i·M_i·t_i\),那么就有:
\(\left\{\begin{matrix} a_j·M_j·t_j\% m_i=0,j\ne i \\ a_j·M_j·t_j\% m_i=a_i,j=i \end{matrix}\right.\)
所以就使所有线性同余方程组都满足 \(x_0\% m_i=a_i\),这个是特解。
2、特解:\(x_0=\sum_{i=1}^{n}a_i·M_i·t_i\)。
3、通解:\(x=x_0+k·M(k=1,2,3,...)\),其中最小整数解 \(ans=x\%M\)。
4、题目链接:洛谷P1495。
void exgcd(i128 a, i128 b, i128 &x, i128 &y) {
if (!b) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
void solve()
{
int n;
cin >> n;
vector<i128> a(n + 1), md(n + 1);
i128 M = 1;
for (int i = 1; i <= n; i++) {
read(a[i], md[i]);
M *= a[i];
}
vector<i128> m(n + 1), t(n + 1);
for (int i = 1; i <= n; i++) {
m[i] = M / a[i];
i128 y;
exgcd(m[i], a[i], t[i], y);
t[i] %= a[i];
t[i] = (t[i] + a[i]) % a[i];
}
i128 ans = 0;
for (int i = 1; i <= n; i++) {
ans = (ans + (md[i] * m[i] % M * t[i] % M)) % M;
}
ans = (ans + M) % M;
write(ans, '\n');
}
EXCRT
1、和 \(crt\) 的区别就是不满足所有的 \(m_i\) 两两之间互质了,解决方法也很简单,首先假设我们有 \(k\) 组线性同余方程,现在我们求出了 \(k-1\) 组的通解为 \(x=r1+k1·M,(k1=1,2,3,...)\),现在假设我们找到了一个通解 \(k1=t\),使得 \((r1+t·M)\% m_k=r_2\),那么 \(k\) 组线性同余方程的通解则为 \(x=r1+t·M+k_2·lcm(M,m_k),(i=1,2,3,...)\)。
2、另外,如何求解这个 \(t\) 呢,那么就需要用到我们的扩展欧几里得了,我能将式子拆成别的形式,可以得到 \(M·t+m_k·y=r2-r_1\),其中 \(gcd(M,m_k)\ |\ (r_2-r_1)\),如果不满足,则说明无解。现在我们就可以得到通解里面的 \(t=t·\frac{r_2-r_1}{gcd(M,m_k)}\),不过这里得龟速乘,否则会爆 \(longlong\),另外还有个值的注意的是,我们需要将 \(r_2-r_1\) 化为非负数,否则会导致快速乘 \(tle\)。
3、题目链接:洛谷P4777。
void exgcd(i128 a, i128 b, i128 &x, i128 &y) {
if (!b) {
x = 1;
y = 0;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
}
void solve()
{
int n;
read(n);
vector<i128> a(n + 1), b(n + 1);
i128 M, r;
for (int i = 1; i <= n; i++) {
read(a[i], b[i]);
if (i == 1) {
M = a[i];
r = b[i];
}
}
for (int i = 2; i <= n; i++) {
i128 d = __gcd(M, a[i]);
i128 t, y;
exgcd(M, a[i], t, y);
t %= a[i];
i128 res = b[i] - r;
assert(res % d == 0);
t = t * (res / d) % a[i];
t = (t + a[i]) % a[i];
i128 LCM = M * a[i] / d;
r = (r + (t * M % LCM)) % LCM;
r = (r + LCM) % LCM;
M = LCM;
}
write(r, '\n');
}
具体的详细内容可见这位大佬的博客:传送门。

浙公网安备 33010602011771号