数论-中国剩余定理(crt) 与拓展中国剩余定理(excrt)

版权声明:转载请留言 https://blog.csdn.net/qq_40744093 https://blog.csdn.net/qq_40744093/article/details/87967270

中国剩余定理(crt)

[用途]

求方程组中最小的非负整数解X
X   { a 1 ( m o d m 1 ) a 2 ( m o d m 2 ) . . . a n ( m o d m n ) X\ \equiv\left\{\begin{array}{cc} a_{1} \quad (mod \quad m_{1})\\ a_{2} \quad (mod \quad m_{2})\\ ...\\ a_{n} \quad (mod \quad m_{n}) \end{array}\right.
其中 m i , m j m_{i},m_{j} 两两互素

[引入]

韩信点兵:

韩信带1500名兵士打仗,战死四五百人,站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信很快说出人数:1049。


X   { 2 ( m o d 3 ) 4 ( m o d 5 ) . . . 6 ( m o d 7 ) X\ \equiv\left\{\begin{array}{cc} 2 \quad (mod \quad 3)\\ 4 \quad (mod \quad 5)\\ ...\\ 6 \quad (mod \quad7) \end{array}\right.

解得 X = 1049 X=1049

[结论]

X = 1 n ( a i t i M i ) ( m o d L c m ) X=\sum_{1}^{n}(a_{i}t_{i}M_{i}) \quad (mod \quad Lcm)
其中:
最小公倍数 L c m = m 1 m 2 . . . m n Lcm=m_{1}m_{2}...m_{n} ,因为 m i , m j m_{i},m_{j} 两两互素
M i = L c m / m i M_{i}=Lcm/m_{i}
t i ti M i M_{i} m i m_{i} 意义下的乘法逆元
【证明】
其中的 M M 就是 L c m Lcm
百度百科
在这里插入图片描述
最终就是 X = 1 n ( a i t i M i ) ( m o d L c m ) X=\sum_{1}^{n}(a_{i}t_{i}M_{i}) (mod \quad Lcm)

[代码]

typedef long long LL;
void exgcd(LL a,LL b,LL &x,LL &y)
{
	if(!b){
		x=1;
		y=0;
		return;
	}
	exgcd(b,a%b,y,x);
	y-=a/b*x;
	return;
}
LL crt(LL Lcm,LL len)						/*Lcm:最小公倍数;len:m[]数组长度*/ 
{
	LL ans=0;
	for(int i=1;i<=len;++i){
		LL Mi=Lcm/m[i];						/*j从1~len,除i外,所有m[j]的乘积*/ 
		LL ti,y;
		exgcd(Mi,m[i],ti,y);				/*ti为Mi在模m[i]意义下的乘法逆元*/ 
		ans=((ans+a[i]*ti*Mi)%Lcm+Lcm)%Lcm; /*结论*/ 
	}
	return ans;
}

拓展中国剩余定理(excrt)

与中国剩余定理不同的是 不一定 两两互素

[结论]

通解 X = x 0 ( m o d L c m ) X=x_{0} (mod \quad Lcm)
特解 x 0 = a 1 + t 1 m 1 x_{0}=a_{1}+t_{1}m_{1}

[证明]

以下出现的字母均为整数

a i 余数:a_{i}
m i 模数:m_{i}
g c d ( m 1 , m i ) = g c d 假设:gcd(m_{1},m_{i})=gcd
x 0 = { a 1 + t m 1 a i + t i m i x_{0}=\left\{\begin{array}{cc} a_{1} +tm_{1}\\ a_{i} +t_{i}m_{i} \end{array}\right.
移向可得: t m 1 + ( t i ) m i = a i a 1 tm_{1}+(-t_{i})m_{i}=a_{i}-a_{1}
根据不定方程(丢番图方程)
二元一次不定方程的一般形式为ax+by=c。其中 a,b,c 是整数,ab ≠ 0。此方程有整数解的充分必要条件是a、b的最大公约数整除c。设x,y是该方程的一组整数解,那么该方程的通解可表示为
x = x 0 + b g c d ( a , b ) t ; y = y 0 b g c d ( a , b ) t ; x=x_{0}+\frac{b}{gcd(a,b)}t;y=y_{0}-\frac{b}{gcd(a,b)}t;
所以对于 t m 1 + ( t i ) m i = a i a 1 tm_{1}+(-t_{i})m_{i}=a_{i}-a_{1}
t 1 t_{1} 有解则有: ( a i a 1 ) ÷ g c d = 0 (a_{i}-a_{1}) \div gcd=0
t = t 0 + m i g c d k t=t_{0}+\frac{mi}{gcd}k
t t 0 ( m o d m i g c d ) t\equiv t_{0}(mod \quad \frac{mi}{gcd})
T m 1 + ( T i ) m i = g c d Tm_{1}+(-T_{i})m_{i}=gcd 先用拓展欧几里得求 T T
进而 t = T a i a 1 g c d ( m o d m [ i ] g c d ) t=T\frac{a_{i}-a_{1}}{gcd}(mod\quad \frac{m[i]}{gcd})
则特解 x 0 = a 1 + t m 1 x_{0}=a_{1}+tm_{1}


对于通解X与特解 x 0 x_{0} 满足:
{ X = a 1 + k 1 m 1 x 0 = a 1 + k 2 m 1 \left\{\begin{array}{cc} X=a_{1} +k_{1}m_{1}\\ x_{0}=a_{1} +k_{2}m_{1} \end{array}\right. { X = a 2 + k 3 m 2 x 0 = a 2 + k 4 m 2 \left\{\begin{array}{cc} X=a_{2} +k_{3}m_{2}\\ x_{0}=a_{2} +k_{4}m_{2} \end{array}\right.
上式减去下式得
X x 0 = ( k 1 k 2 ) m 1 = ( k 3 k 4 ) m 2 X-x_{0}=(k_{1}-k_{2})m_{1}=(k_{3}-k_{4})m_{2}
X x 0 = K 1 m 1 = K 2 m 2 X-x_{0}=K_{1}m_{1}=K_{2}m_{2}
假设 n 1 = m 1 g c d , n 2 = m 2 g c d n_{1}=\frac{m_{1}}{gcd},n_2=\frac{m_{2}}{gcd} ,显然 g c d ( n 1 , n 2 ) = 1 ; gcd(n_{1},n_{2})=1;
K 1 n 1 = K 2 n 2 K_{1}n_{1}=K_{2}n_{2}
K 1 = K 2 n 2 n 1 K_{1}=\frac{K_{2}n_{2}}{n_{1}}
g c d ( n 1 , n 2 ) = 1 , K 1 gcd(n_{1},n_{2})=1,K_{1}为整数
所以 K 2 % n 1 = 0 K_{2} \% n_{1}=0
两边同乘 n 2 g c d n_{2}gcd
K 2 n 2 g c d % n 1 n 2 g c d = 0 K_{2}n_{2}gcd\% n_{1}n_{2}gcd =0
X x 0 = K 2 m 2 = K 2 n 2 g c d X-x_{0} =K_{2}m_{2}=K_{2}n_{2}gcd
n 1 n 2 g c d = n 1 g c d n 2 g c d g c d = L c m ( m 1 , m 2 ) = L c m n_{1}n_{2}gcd=\frac{n_{1}gcd n_{2}gcd}{gcd}=Lcm(m_{1},m_{2})=Lcm
所以 ( X x 0 ) % L c m = 0 (X-x_{0}) \% Lcm=0
即通解 X x 0 ( m o d L c m ) X\equiv x_{0}(mod \quad Lcm)

[代码]

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const LL N=1e5+9;
LL a[N],m[N];
LL ksc(LL x,LL y,LL mod)
{
	return (x*y-(LL)((long double)x*y/mod)*mod+mod)%mod;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
	if(!b){
		x=1;
		y=0;
		return a;
	}
	LL gcd=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return gcd;
}
LL excrt(LL len)
{
	LL x=a[1],Lcm=m[1],t,y;			/*一个方程时,x=a[1],Lcm=m[1]*/
	for(int i=2;i<=len;++i){
		a[i]-=x;					/*求a[i]-a[1]*/
		LL gcd=exgcd(Lcm,m[i],t,y); /*求gcd与证明过程中的T*/
		if(a[i]%gcd)return -1;	 	/*方程无解*/
		t=ksc(t,a[i]/gcd,m[i]/gcd); /*O(1)快速乘求t*/
		x+=t*Lcm;					/*求特解x0*/
		Lcm*=m[i]/gcd;				/*更新Lcm*/
		x=(x%Lcm+Lcm)%Lcm;			/*更新通解*/
	}
	return x;						/*均按照上述证明步骤*/ 
}
int main()
{
	ios::sync_with_stdio(false);
	LL n;
	while(cin>>n){
		memset(a,0,sizeof(a));
		memset(m,0,sizeof(m));
		for(int i=1;i<=n;++i)cin>>m[i]>>a[i];
		cout<<excrt(n)<<endl;
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_40744093/article/details/87967270