拓展中国剩余定理(exCRT)
Warning
本笔记没有处理无解的情况,需要注意的是当判断无解时, \(a_2 - a_1\) 需要对 \(m_2\) 取余,来保证最终累加答案的非负性。
虽然在必定有解的情况下可能也会出现这个问题,但是洛谷的模板题数据未能体现,导致模板错误
下面的模板已经订正
update 2023-07-18
算法分析
由于exCRT完美的平替了CRT的全部功能,故不再详细复习CRT的相关内容.
考虑如下同余方程组,
\[\begin{cases}
x \equiv a_1 \pmod{m_1} \\
x \equiv a_2 \pmod{m_2} \\
\end{cases}
\]
展开得,
\[a_1 + k_1 \times m_1 = a_2 + k_2 \times m_2
\]
\[\Rightarrow k_1 \times m_1 - k_2 \times m_2= a_2 - a_1
\]
该式子左侧类似裴蜀定理, 则存在 \(\lambda_1, \lambda_2\) 满足 \(\lambda_1 \times m_1 + \lambda_2 \times m_2= gcd(m_1, m_2)\)
当 \(gcd(m_1, m_2) \nmid a_2 - a_1\) 时, 方程组无解.
当 \(gcd(m_1, m_2) \mid a_2 - a_1\) 时, 存在 \(k_1 , k_2\) 满足 \(k_1 \times m_1 - k_2 \times m_2= a_2 - a_1\).
则特解 \(x^* = \frac{a_2 - a_1}{gcd(m_1, m_2)} \times \lambda_1 \times m_1\), 根据CRT的相关内容,得到通解
\[x = \frac{a_2 - a_1}{gcd(m_1, m_2)} \  \lambda_1 \ m_1 + k_1 \cdot lcm(m_1, m_2)
\]
考虑由多个同余方程组成的方程组,上面通解可表达成
\[x \equiv \frac{a_2 - a_1}{gcd(m_1, m_2)} \  \lambda_1 \ m_1 \pmod{lcm(m_1, m_2)}
\]
由此,以此从方程组中选出两个同余方程进行合并,显然不失一般性。
Code
点击查看代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5 + 50;
typedef long long lld;
inline int read() {
	register int w = 0, f = 1;
	register char c = getchar();
	while (c > '9' || c < '0') {
		if (c == '-')  f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		w = w * 10 + c - '0';
		c = getchar();
	}
	return w * f;
}
int n;
lld a1, a2, m1, m2;
inline lld gcd(register lld a, register lld b) {
	return (!b ? a : gcd(b, a % b));
}
inline lld mul(register lld a, register lld b, register lld p) {
	lld ans = 0;
	while (b) {
		if (b & 1)  ans = (ans + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return ans;
}
inline lld exgcd(register lld a, register lld b, lld &x, lld &y) {
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	register lld g = exgcd(b, a % b, x, y);
	register lld tmp = x;
	x = y;
	y = tmp - a / b * y;
	return g;
}
int main(){
	n = read();
	scanf("%lld%lld", &m1, &a1);
	for (register int i = 2; i <= n; ++i) {
		scanf("%lld%lld", &m2, &a2);
		register lld x, y;
		register lld g = exgcd(m1, m2, x, y);
		register lld res = ((a2 - a1) % m2 + m2) % m2;
		if (res % g) {
			printf("No Solution\n");
			return 0;
		}
		register lld tmp = m1 / g * m2;
		a1 = (a1 + mul(mul(res / g, x, tmp), m1, tmp) + tmp) % tmp;
		m1 = tmp;
	}
	printf("%lld\n", a1);
	return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号