中国剩余定理(CRT) 简记

Introduction

给定 \(n\) 组关于 \(x\) 的一元线性同余方程组:

\[\begin{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} \]

其中对于 \(\forall i,j \in [1,n] \text{ and } i \ne j\) 满足 \(\gcd(m_i,m_j) = 1\)

求其最小非负整数解。

Chinese Remainder Theorem

\(M = \prod_{i=1}^n m_i , M(i) = \frac{M}{m_i} , t_i\) 为方程 \(M(i) \times t_i \equiv 1 \pmod{m_i}\) 的一个解。

那么上述方程组的解为

\[x = \sum\limits_{i=1}^n a_i t_i M(i) \]

但这只是一个解,如果要求最小整数解呢?很简单,只要将 \(x\)\(M\) 取模即可。

Code

模板题:Luogu P1495 【模板】中国剩余定理(CRT)/曹冲养猪

#include<iostream>

using std::cin;
using std::cout;
using std::endl;

typedef long long ll;
void exgcd(ll a,ll b,ll &c,ll &x,ll &y){
	if(!b){c=a,x=1ll,y=0ll;return;}
	exgcd(b,a%b,c,y,x),y-=x*(a/b);
}
ll inv(const ll &b,const ll &p){
	ll c,x,y;  exgcd(b,p,c,x,y);
	return c==1ll?(x+p)%p:-1ll;
}

const int N=12;
int m[N],a[N],n;
int t[N];
ll M=1ll;

signed main() {
	cin>>n;
	for(register int i=1;i<=n;i++) {
		cin>>m[i]>>a[i];
		M*=m[i];
	}
	for(register int i=1;i<=n;i++)
		t[i]=inv(M/m[i],m[i]);
	
	ll ans=0ll;
	for(register int i=1;i<=n;i++)
		ans+=a[i]*(M/m[i])*t[i];
	
	cout<<(ans+M)%M<<endl;
	return 0;
}

Proof

为什么这个解是可行的?

\(M(i)\) 的定义可知:

\(\forall i \in [1,n] , \begin{cases} {a_i t_i M(i) \equiv 0 \pmod{m_j}} & i\ne j \\ {a_i t_i M(i) \equiv a_i \pmod{m_j}} & i=j \end{cases}\)

显然, \(x = \sum_{i=1}^n a_i t_i M(i)\) 就是方程的解。

为什么只需对 \(M\) 取模就能得到最小整数解?

\(x\) 就是上述得到的特殊解。

那么,由于 \(m_{1\cdots n}\) 两两互质,因此方程组的解集可表示为:

\[\{ x + kM | k \in \mathbf{Z} \} \]

因此,在 \([0,M)\) 范围内只存在唯一解,而且同时是最小非负整数解。那么将得到的特殊解对 \(M\) 取模即可。

猜你喜欢

转载自www.cnblogs.com/-Wallace-/p/12616339.html