AcWing 204 题解(中国剩余定理)

传送门

\(\color{black}{AcWing 204}\)

题面:

给你两个长度为\(n\)的数组\(a,m\),要求你找到一个数字\(x\)满足对于每一个\(i (1 \leq i \leq n)\),都有\(x ≡ m_i (\mod a_i)\)

\(x\)输出。

思路(推导过程):

首先我们看一下第一个式子和第二个式子
\(x \mod a_1 = m_1, x \mod a_2 = m_2\)
得到:\(x = k_1\times a_1 + m_1 = k_2\times a_2 + m_2\)
得到:\(k_1\times a_1 - k_2\times a_2 = m_2 - m_1\)
那么如果\((m_2-m_1)\mod \gcd(a_1, a_2) \neq 0\)说明无解,否则(跨过大金字)继续往下
我们用扩展欧几里得算法做\(a_1,a_2\)时,会计算出两个数,就是\(k_1,k_2\)
然后\(x = (k_1 + k \times a_2 ÷ d) \times a_1 + m_1\)\(k\)是某一个数字)
那么\(x = k_1 \times a_1 + m_1 + k \times a_1 \times a_2 ÷ d\)
接下来跨过大金字
那么也就等于 \(x = k_1 \times a_1 + m_1 + k \times lcm(a_1,a_2)\)
我们把\(k_1 \times a_1\) 记为 \(x_0\),把 \(lcm(a_1,a_2)\) 记为 \(a\)
那么\(x = x_0 + k \times a\)
上述是合并两个式子,其实合并\(n\)个式子也同理,无非就是多合并几次嘛
总的来说,最后的形式也是\(x =x_0+k \times a\)
那么\(x \mod a ≡ x_0\)
那么要求的就是\(x_0 \mod a\) 的正余数

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int exgcd(int a, int b, int& x, int& y) 
{
	if (b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	int x1, y1;
	int d = exgcd(b, a % b, x1, y1);
	x = y1;
	y = x1 - a / b * y1;
	return d;
}
signed main()
{
	int n;
	cin >> n;
	int a1, m1;
	cin >> a1 >> m1;  
	bool flag = false;          
	for (int i = 2; i <= n; i++)
	{
		int a2, m2;
		cin >> a2 >> m2; 
		int k1, k2;
		int d = exgcd(a1, a2, k1, k2);
		if ((m1 - m2) % d != 0) // 无解
		{
			flag = true;
		}
		// 下面可以直接按照推导公式去做。
		k1 *= ((m2 - m1) / d);
		int t = (a2 / d); 
		k1 = (k1 % t + t) % t; //  注意直接模可能会导致负数,要模完之后再加模数在模一次。
		
		m1 += a1 * k1;
		a1 = abs(a1 / d * a2);
	}
	if (flag) cout << -1 << endl; // 无解输出-1
	else cout <<(m1 % a1 + a1) % a1 << endl;  //  注意直接模可能会导致负数,要模完之后再加模数在模一次。
	return 0;
} 
posted @ 2025-07-24 16:26  MichaelZeng  阅读(15)  评论(0)    收藏  举报