中国剩余定理及扩展

挂链接

中国剩余定理

\(m_1, m_2, ..., m_k\)两两互质
则对于方程组
\(x\equiv a_1 (mod\ m_1)\)
\(x\equiv a_2 (mod\ m_2)\)
\(...\)
\(x\equiv a_k (mod\ m_k)\)
有整数解
并且在模\(M=\Pi m_i\)的意义下解唯一
\(\sum(a_i*M/m_i)(mod\ M)\)

\(Exgcd\)一波求解就好了

证明:
对于方程组
\(x\equiv 0 (mod\ m_1)\)
\(x\equiv 0 (mod\ m_2)\)
\(...\)
\(x\equiv 1 (mod\ m_i)\)
\(...\)
\(x\equiv 0 (mod\ m_k)\)
就等价于求解
\((M/m_i)x\equiv 1(mod\ m_i)\)

而如果\(x\equiv c(mod\ m_i)\)
那么\(a*x\equiv a*c(mod\ m_i)\)

扩展

求解模数不互质情况下的线性方程组

考虑合并两个方程组
\(x\equiv a_i (mod\ m_i)\)
\(x\equiv a_{i+1} (mod\ m_{i+1})\)

写成
\(x=a_i+x_1*m_i=a_{i+1}+x_2*m_{i+1}\)
的形式
\(x\)最小,那么可以先解出\(x_1\)最小的解\(x'\),带入就是
直接\(Exgcd\)求解\(x_1*m_i+x_2*m_{i+1}=a_{i+1}-a_i\),就好了

合并之后
显然新的方程就是
\(x\equiv x' (mod\ lcm(m_i, m_{i+1}))\)

就可以了

代码

POJ2891

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

template <class Int>
IL void Input(RG Int &x){
    RG int z = 1; RG char c = getchar(); x = 0;
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    x *= z;
}

IL ll ExGcd(RG ll a, RG ll b, RG ll &x, RG ll &y){
	if(!b){
		x = 1, y = 0;
		return a;
	}
	RG ll d = ExGcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}

const int maxn(1e5 + 5);

int n, flg;
ll ans, x, y, m[maxn], b[maxn];

int main(RG int argc, RG char* argv[]){
	while(scanf("%d", &n) != EOF){
		ans = flg = 0;
		for(RG int i = 1; i <= n; ++i) Input(m[i]), Input(b[i]);
		for(RG int i = 2; i <= n; ++i){
			RG ll d = ExGcd(m[1], m[i], x, y), g = b[i] - b[1], t;
			if(g % d){
				flg = 1;
				break;
			}
			x *= g / d, t = m[i] / d, x = (x % t + t) % t;
			b[1] += m[1] * x, m[1] *= t, b[1] %= m[1];
		}
		if(flg) puts("-1");
		else printf("%lld\n", (b[1] % m[1] + m[1]) % m[1]);
	}
    return 0;
}
posted @ 2018-04-10 22:28  Cyhlnj  阅读(175)  评论(0编辑  收藏  举报