扩展中国剩余定理

问题引入

求解方程

[egin{cases} x &equiv a_1 pmod{m_1} \ x &equiv a_2 pmod{m_2} \ & vdots \ x &equiv a_n pmod{m_n} \ end{cases} ]

其中 (m_1,m_2,...,m_n) 两两互质

中国剩余定理 ( ext{CRT})

(M = prod_{i=1}^n m_i,n_i = frac M {m_i})
找到 (c_i) 使 (c_i n_i equiv 1 pmod{m_i})
那么特解 (x_0 = sum_{i=1}^n a_i n_i c_i pmod M)
通解表示为 (x = k M + x_0) 在模 (M) 意义下恒等

扩展 ( ext{exCRT})

模数不两两互质的情况
考虑两个方程 (x equiv a_1 pmod{m_1},x equiv a_2 pmod{m_2})
化为不定方程 (x = k_1 m_1 + a_1 = k_2 m_2 + a_2)
移项得到 (m_1 k_1 - m_2 k_2 = a_2 - a_1)
求解这个不定方程,(g=gcd(m_1,m_2))
(k_1 frac{m_1}g - k_2 frac{m_2}g = frac{a_2 - a_1}g)
扩欧求特解 (p_0,q_0)
通解为 (p = p_0 + t frac{m_2}g ,q = q_0 + t frac{m_1}g)
那么选取 (p) 在模 (frac{m_2}g) 意义下的最小正整数解表示出答案 (x equiv m_1 p + a_1 pmod{lcm(m_1,m_2)})
于是我们将原始的两个方程合并成了这样的一个方程
同理与后面的方程进行合并即可

( ext{Code})

#include<cstdio>
#define LL long long
using namespace std;

const int N = 1e5 + 5;
int n;
LL a[N] , b[N];

LL qmul(LL x, LL y, LL P)
{
	LL ret = 0;
	if (y < 0) y = (y % P + P) % P;
	for(; y; y >>= 1)
	{
		if (y & 1) ret = (ret + x) % P;
		x = 2 * x % P;
	}
	return ret;
}

LL exgcd(LL a, LL b, LL &x, LL &y)
{
	if (!b)
	{
		x = 1, y = 0;
		return a;
	}
	LL d = exgcd(b, a % b, x, y);
	LL t = x - a / b * y; x = y, y = t;
	return d;
}

LL exCRT()
{
	LL B = b[1], A = a[1], M, x, y, d, c;
	for(int i = 2; i <= n; i++)
	{
		d = exgcd(A, a[i], x, y);
		c = a[i] / d;
		x = (qmul(x, (b[i] - B) / d, c) + c) % c;
		M = A / d * a[i];
		B = (qmul(x, A, M) + B) % M, A = M;
	}
	return B;
}

int main() 
{
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%lld%lld", a + i, b + i);
	printf("%lld
", exCRT());
}
原文地址:https://www.cnblogs.com/leiyuanze/p/14581848.html