中国剩余定理及其扩展定理 学习笔记
中国剩余定理及其扩展定理 学习笔记
中国剩余定理,又叫孙子定理,最早出现在我国古代著作《孙子算经》中,OI 中常称其为 CRT(China Remainder Theorem)。
问题
CRT 用于求解线性同余方程组问题,且模数互质:
求 \(x\) 的最小非负整数解。
CRT
令 \(m_i = \dfrac{\prod_{j = 1}^n a_j}{a_i}, r_i\equiv m_i^{-1}\pmod {a_i}\)。
则 \(x_0\) 是一个特解,通解形式如下,因为对于每一个 \(a_i\) 都有 \(a_i | \prod a_i\):
显然地,最小的非负整数解就是 \((x_0\bmod \prod a_i + \prod a_i) \bmod \prod a_i\)。
这其实是一个构造性的算法,接下来证明 \(x_0\) 是方程的解。
证明:\(\forall i\in[1, n]\),\(x\equiv b_i\pmod {a_i}\),\(x_0\) 是其一个解。
对于 \(j\ne i, a_i | m_j\),所以 \(x_0\equiv b_im_ir_i\pmod {a_i}\)。
又 \(m_ir_i\equiv 1\pmod{a_i}\),所以 \(x_0\equiv b_i\pmod {a_i}\).
注意到 \(r_i\) 为 \(m_i\) 在 \(\bmod a_i\) 意义下的逆元,由于 \(a\) 序列互相互质,所以一定存在逆元,但在去掉这个限制的情况下,逆元不存在,无法通过 CRT 求解。
ExCRT
用于解决线性同余方程组模数不互质的情况,ExCRT 其实和 CRT 没什么关系。
考虑一个同余方程组:
如果能把它们两个合并成一个方程,然后迭代地合并所有方程,最后得到一个唯一的同余方程,岂不美哉?
先考虑把方程拿出同余系:
发现这是一个 ExGcd(aka 裴蜀定理)的形式,方程无解当且仅当 \(\gcd(a_1, a_2) \nmid (b_2 - b_1)\),于是可以通过 ExGcd 求出 \(p, q\) 的特解,设其为 \(p_0, q_0\),则 \(p, q\) 的通解为:
所以把通解代入一开始其中一个方程中得到:
至此,我们将两个同余方程合并为一个同余方程,重复 \(n - 1\) 次合并,最终剩下一个同余方程,这样最小正整数解就呼之欲出了。
C++ 实现
Problem: P4777 【模板】扩展中国剩余定理(EXCRT)
// Problem: P4777 【模板】扩展中国剩余定理(EXCRT)
// Contest: Luogu
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-11-11 13:26:13
#include <algorithm>
#include <iostream>
#define int long long
#define ll __int128
using namespace std;
const int N = 1e5 + 10;
int n, p[N], a[N];
int exgcd(ll a, ll &x, ll b, ll &y) {
if(!b) return x = 1, y = 0, a;
ll d = exgcd(b, y, a % b, x);
return y -= a / b * x, d;
}
int excrt() {
for(ll i = n - 1, k1, k2, d; i; i --) {
d = __gcd(p[i], p[i + 1]);
if((a[i + 1] - a[i]) % d) return -1; // 本题中不存在无解,但是无解情况不要漏
exgcd(p[i], k1, p[i + 1], k2);
k1 = k1 * (a[i + 1] - a[i]) / d % (p[i + 1] / d);
a[i] += k1 * p[i], p[i] = p[i] / __gcd(p[i], p[i + 1]) * p[i + 1], a[i] %= p[i];
}
return (a[1] % p[1] + p[1]) % p[1];
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++) cin >> p[i] >> a[i];
cout << excrt() << '\n';
return 0;
}