1. 程式人生 > 其它 >CRT & EXCRT 學習筆記

CRT & EXCRT 學習筆記

這玩意解決的是把同餘方程組合並的問題。
CRT的核心思想和拉格朗日插值差不多,就是構造一組\(R_i\)使得$\forall i,j(i \neq j) $

\[R_im_i = 1, R_im_j = 0 \]

有了思路後這玩意隨便構造一下就出來了,式子裡面出現了一些奇怪的逆元,所以要求模數互質
現在考慮擴充套件CRT,模數不互質了
本質思路是合併兩個同餘方程組
發現同餘條件等價於\(x=k_1m_1+a_1=k_2m_2+a_2\)
怎麼求出其中的一個\(k\)呢?其實也就是\(k_1m_1-k_2m_2=a_2-a_1\)
擴充套件歐幾里得即可

Code

#include <cstdio>
#include <iostream>
#define LL long long 
using namespace std;
inline LL read() {
	LL res = 0, flag = 0; char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') flag = 1;
	for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch ^ 48);
	if(flag) res = ~res + 1;
	return res;
}
inline LL gcd(LL x, LL y) {return y ? gcd(y, x % y) : x;}
inline void exgcd(LL a, LL b, LL &x, LL &y) {
	if(!b) x = 1, y = 0;
	else exgcd(b, a % b, y, x), y -= a / b * x;
}
LL n, a, m, A, M;
int main() {
	n = read(), m = read(), a = read(); 
	for(int i = 2; i <= n; ++i) {
		M = read(), A = read(); 
		LL d = gcd(m, M), t = A - a, x, y, mod;
		if(t % d) return 0;
		exgcd(m, M, x, y);
		x = t / d * x % (M / d);
		if(x < 0) x += M / d;
		mod = m / d * M;
		a = (x * m + a) % mod;
		if(a < 0) a += mod;
		m = mod;
	} 
	printf("%lld\n",a);
}