其他分享
首页 > 其他分享> > 孙子定理

孙子定理

作者:互联网

孙子定理

孙子定理,又称之为中国剩余定理(Chinese Remainder Theorem, CRT)可以求解如下形式的一元线性同余方程组(其中\(n_1,n_2,\dots,n_k\)两两互质)。

\[\begin{cases} x\equiv a_1(mod\:n_1)\\ x\equiv a_2(mod\:n_2)\\ \quad\quad \vdots \\ x\equiv a_k(mod\:n_k)\\ \end{cases} \]

中国剩余定理说明:假设整数\(m_1,m_2,\dots,m_n\)两两互质,则对任意的整数:\(a_1,a_2,\dots,a_n\),方程组有解,并且我们可以用如下方式构造得到:

设\(M=m_1\times m_2\times\dots\times m_n=\prod_{i=1}^{n}m_i\)是整数\(m_1,m_2,\dots,m_n\)的乘积,并设\(M_i=\frac{M}{m_i},\forall i\in\{1,2,3,\dots,n\}\)是除了\(m_i\)以外的\(n-1\)个整数的乘积。设\(t_i\)是\(M_i\)模\(m_i\)下的逆元,则方程组的通解形式为:\(x=a_1t_1M_1+a_2t_2M_2+\dots+a_nt_nM_n+kM=kM+\sum_{i=1}^na_it_iM_i,k\in Z\)。
所以在模\(M\)的意义下,方程组的只有一个解:\(x=(\sum_{i=1}^na_it_iM_i)(mod\:M)\)。

算法流程:

  1. 计算所有模数的积\(n\);(有的上面说计算它们的最小公倍数,其实都一样它们两两互质)
  2. 对于第\(i\)个方程:
    1. 计算\(m_i=\frac{n}{n_i}\);
    2. 计算\(m_i\)在模\(n_i\)意义下的逆元\(m_i^{-1}\);
    3. 计算\(C_i=m_i\times m_i^{-1}\)(不要对\(n_i\)取模);
  3. 方程组的唯一解为:\(a=\sum_{i=1}^ka_i\times c_i(mod\:n)\)。
void exgcd(ll a, ll b, ll &x, ll &y){//扩展欧几里得 
	if(b == 0){
		x = 1;
		y = 0;
		return ;
	}
	exgcd(b,a%b,x,y);
	ll temp = x;
	x = y;
	y = temp - a / b * y;
	return ;
}

ll qmul(ll n, ll b, ll mod){
	ll res = 0;
	b = b % mod;
	while(n > 0){
		if(n & 1) res = (res + b) % mod;
		b = (b + b) % mod;
		n >>= 1;
	}
	return res % mod;
}

ll CRT(){
	ll M = 1, res = 0; 
	for(int i = 1; i <= n; i++){
		M *= m[i];
	}
	for(int i = 1; i <= n; i++){
		ll x, y;
		ll Mi = M / m[i];
		exgcd(Mi,m[i],x,y);
		x = (x % m[i] + m[i]) % m[i];//防止x为负数
		res = (res + qmul(qmul(Mi,x,M),a[i],M)) % M;//使用快速幂不然有的会爆long long
	}
	if(res < 0) res += M;
	return res;
}

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

\[\begin{cases} x\equiv a_1(mod\:m_1)\:\:\:(1)\\ x\equiv a_2(mod\:m_2)\:\:\:(2)\\ \end{cases} \]

将\(1,2\)两式合并我们可以得到:\(m_1\times x_1+a_1=m_2\times x_2+a_2\),即\(m_1\times x_1+(-m_2)\times x_2=a_2-a_1\)。运用扩展欧几里得算法,我们可以算出\(x_1,x_2\)进而我们可以知道\(x_1,x_2\)的解集\(x_1=x_1+k\times\frac{m_2}{d},x_2=x_2+k\times\frac{m_1}{d}\)(\(k\)为任意常数)。其中\(gcd(m_1,m_2)=d\),并且我们知道\(gcd(m_1,m_2)|(a_2-a_1)\),否则无解。这里对于\(x_1,x_2\)解集的证明可以自行证明。

接下来,将\(x_1\)的解集单独带入\((1)\)式中:\(x=m_1\times x_1+a_1+k\times\frac{m_1\times m_2}{d}\)。这里我们知道\(m_1,x_1,a_1,[m_1,m_2]\)的值是已经确认的,只有\(k\)的值是不定的,所以我们可以将式子看成\(x=x_0+k\times a\)(即\(x\equiv x_0(mod\:a)\))。所以我们不断重复\(n-1\)次,即可将\(n\)个式子合并,所以最后的结果为\(x_0\:mod\:a\)。

代码如下:

ll CHT(){
	ll a1 = a[1], m1 = m[1];
	for(ll i = 2; i <= n; i++){
		ll a2 = a[i], m2 = m[i];
		ll x, y;
		ll gcd = exgcd(m1,m2,x,y);
		ll c = a2 - a1;
		if(c % gcd){
			return 0;//无解 
		}
		x = x * c / gcd;
		ll temp = abs(m2/gcd);
		x = (x % temp + temp) % temp;
		a1 = x * m1 + a1;
		m1 = abs(m1 * m2 / gcd);
	}
	return (a1 % m1 + m1) % m1;
}

标签:dots,res,定理,times,孙子,equiv,ll,mod
来源: https://www.cnblogs.com/hy2001/p/14823716.html