扩展中国剩余定理模板

模板代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1000005; const int inf = 0x3f3f3f3f; ll ai[maxn], bi[maxn]; int n; ll mul(ll a, ll b, ll mod) {//快速乘 ll res = 0; while (b>0) { if (b & 1) { res = (res + a) % mod; } a = (a + a) % mod; b >>= 1; } return res; } ll exgcd(ll a, ll b, ll& x, ll& y) {//扩展欧几里得 ll ans; if (b == 0) { x = 1, y = 0; return a; } ans = exgcd(b, a % b, y, x); y -= a / b * x; return ans; } ll exec() { ll x, y, t, m, ans; m = bi[1], ans = ai[1]; for (int i = 2; i <= n; i++) { ll a = m, b = bi[i], c = (ai[i] - ans % bi[i]+bi[i]) % bi[i]; ll gcd = exgcd(a, b, x, y), bg = b / gcd; if (c % gcd != 0)return -1;//无解情况 x = mul(x, c / gcd, bg); ans += x * m;//解 m *= bg;//lcm ans = (ans % m + m) % m; } return (ans % m + m) % m; } int main() { //freopen("test.txt", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%lld%lld", bi + i, ai + i); } printf("%lld\n", exec()); return 0; }
问题
求解同余方程组
⎩⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎧x≡ a1(modm1)x≡ a2(modm2)x≡ a3(modm3)...x≡ ak(modmk)
其中 m1,m2,m3...mk为不一定两两互质的整数, 求x的最小非负整数解
求解
假设已经求出前k-1个方程组成的同余方程组的一个解为x
且有 M=∏i−1k−1mi
(补充:代码实现中用的就是 M=LCMi−1k−1mi,显然易证这样是对的,还更能防止溢出,上述是为了先方便理解,评论区就别问那么多次了=_=)
则前k-1个方程的方程组通解为 x+i∗M(i∈Z)
那么对于加入第k个方程后的方程组
我们就是要求一个正整数t,使得 x+t∗M≡ak(modmk)
转化一下上述式子得 t∗M≡ak−x(modmk)
对于这个式子我们已经可以通过扩展欧几里得求解t
若该同余式无解,则整个方程组无解, 若有,则前k个同余式组成的方程组的一个解解为 xk=x+t∗M
所以整个算法的思路就是求解k次扩展欧几里得