excrt/扩展中国剩余定理 [学习笔记]
先说 CRT,首先我太菜了不会 CRT
会 exCRT 还要 CRT 干嘛(
考虑若干个等式,\(x = res_i (mod\ mod_i)\)
我们考虑到,前 \(i-1\) 个式子是可以合并成 \(bx + a\) 形式的,即 \(x = a (mod\ b)\)
然后搞一个等式,\(bx + a = res_i (mod\ mod_i)\)
移项,变成 (ax + by) 形式即 \(b * x + mod_i * y = res_i - a\)
根据 exgcd 只能求出来 \(ax + by = \gcd(a,b)\) 符合条件的一组 \((x,y)\)
显然如果 \(res_i - a = 0 (mod\ gcd)\) 才会有解。
我们把 \(x, y\) 乘上 \(\frac{(res_i - a)}{gcd}\)
那么此时的 \(x, y\) 满足 \(b * x + mod_i * y = res_i - a\)
令 \(t = lcm(b, mod_i)\)
\((a+bx)\%t\) 显然是符合条件的解,并且符合两个条件。
所以合并之后的 \(a\) 是 \((a+bx)\%t\),\(b = lcm(b, mod_i)\)
// by Isaunoya
#include <bits/stdc++.h>
using namespace std;
typedef __int128 ll;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
auto excrt = [&](vector <long long> res, vector <long long> mod, int n) {
// x % mod = res
function <void(ll, ll, ll&, ll&)> exgcd = [&](ll a, ll b, ll&x, ll&y) {
if(!b) { x = 1; y = 0; return; }
exgcd(b, a % b, y, x), y -= x * (a / b);
};
function <ll(ll, ll)> gcd = [&](ll a, ll b) {
if(!b) return a;
return gcd(b, a % b);
};
ll a = res[0], b = mod[0], x, y, g, t;
for(int i = 1; i < n; i++) {
exgcd(b, mod[i], x, y), g = gcd(b, mod[i]);
if((res[i] - a) % g) { return (ll)-1ll; }
x = (x * (res[i] - a) / g) % mod[i];
cout << (long long)x << ' ' << (long long)y << '\n';
t = b / g * mod[i];
a = ((a + b * x) % t + t) % t;
b = t;
}
return (ll)(a % b + b) % b;
};
cout << (long long)excrt(res, mod, n) << '\n';
return 0;
}