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;
}
posted @ 2020-05-11 13:18  _Isaunoya  阅读(172)  评论(3编辑  收藏  举报