中国剩余定理推导再理解

中国剩余定理: m1, m2, m3, ... , mk 两两互质:(限制条件) x = a1 (mod m1) x = a2 (mod m2) x = a3 (mod m3) ... x = ak (mod mk) 若令 M = m1 * m2 * m3 * ... * mk Mi = M / mi,Mi(-1) 表示 Mi 模 mi 的逆. 则有解 x = a1 * M1 * M1(-1) + a2 * M2 * M2(-1) + ... + ak * Mk * Mk(-1). 其中Mi的逆元Mi(-1)可以用 Mi * x = 1 (mod mi) 来(扩展欧几里得解线性同余方程). 证明过程如下:(以下证明过程,m 和 a 弄反了,余数是m1, m2, 模数是 a1, a2). x mod a1 = m1; x mod a2 = m2; 即: x = k1 * a1 + m1; x = k2 * a2 + m2; 则: k1 * a1 + m1 = k2 * a2 + m2; 即: k1 * a1 - k2 * a2 = m2 - m1. 有解等价于: gcd (a1, a2) | m2 - m1; exgcd求出k1, k2的值,则 x = k1 * a1 + m1 ; 有不定方程所有解: k1 + k * (a2 / d), k2 + k * (a1 / d); 所以 x 的所有解: x = (k1 + k * (a2 /d )) * a1 + m1 x = a1 * k1 + m1 + k * (a1 * a2 / d) x = (a1 * k1 + m1) + k * [a1, a2]. x = x0 + k * a.
代码实现:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;  // 2e9 的数据好像一般都用long long.

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

int main () {
	int n;
	cin >> n;

	LL a1, m1, a2, m2;
	cin >> m1 >> a1;
	LL x, k1, k2;

	bool flag = 0;
	for (int i = 2; i <= n; i ++ ) {
		
		cin >> m2 >> a2;
	
		int d = exgcd(m1, -m2, k1, k2); // m2 正负无所谓

		if ((a2 - a1) % d) {
			flag = 1;
			break;
		}

		k1 *= (a2 - a1) / d;  
		int t = m2 / d;

		k1 = (k1 % t + t) % t;   // 数据范围卡的很紧,所以k1取最小整数解.


		x = k1 * m1 + a1;
		a1 = x;
		m1 = abs(m1 / d * m2);   // m1正数、负数均可以.
	}

	if(flag) cout << "-1" << endl;
	else cout << (x % m1 + m1) % m1 << endl;  // 答案要求最小整数解.
	return 0;
}

THE END;

经验分享 程序员 微信小程序 职场和发展