中国剩余定理和扩展中国剩余定理

也许更好的阅读体验

文章目录

  • 前置知识
  • 中国剩余定理(CRT)
    • 目的
    • 求法
    • Code
  • 扩展中国剩余定理(EXCRT)
    • 目的
    • 解法
    • code


前置知识

快速乘
扩展欧几里得定理
同余方程

中国剩余定理(CRT)

目的

求最小的正整数 x x x,使其满足

{ x ≡ a 1 ( m o d   m ) x ≡ a 2 ( m o d   m 2 ) ⋮ x ≡ a n ( m o d   m n ) \begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases} xa1(mod m)xa2(mod m2)xan(mod mn)

其中 m 1 , m 2 … m n m_1,m_2\dots m_n m1,m2mn互质

求法

M = ∏ i = 1 n m i \begin{aligned}M=\prod ^{n}_{i=1}m_{i}\end{aligned} M=i=1nmi

ω i = M m i \omega _{i}=\dfrac {M}{m_{i}} ωi=miM

ω i − 1 \omega_i^{-1} ωi1 ω i \omega_i ωi m o d   m i mod\ m_i mod mi下的逆元

则有
x = ∑ i = 1 n a i ω i ω i − 1 m o d   M \begin{aligned}x=\sum ^{n}_{i=1}a_{i}\omega_{i}\omega_{i}^{-1} mod\ M\end{aligned} x=i=1naiωiωi1mod M

当对 m i m_i mi取模时,除了有 ω i \omega_i ωi的项,其余项都是 m i m_i mi的倍数,也就是说它们 m o d   m i mod\ m_i mod mi是为 0 0 0的,最后得到的结果就是 a i a_i ai

m 1 , m 2 … m n m_1,m_2\dots m_n m1,m2mn互质
为了保证是最小正整数解,我们乘以 ω i \omega_i ωi的逆元,这样保证了其不会过大

Code

#define ll long long
#define ull unsigned long long

void ex_gcd (ll a,ll b,ll &x,ll &y)
{
	if (!b){	x=1,y=0;return;}
	ex_gcd(b,a%b,x,y);
	int tmp=x;
	x=y,y=tmp-a/b*y;
}

ll mul (ll x,ll y,const ll mod)//快速乘
{
	x%=mod,y%=mod;
	ll z=(long double)x*y/mod;
	ll ans=(ull)x*y-(ull)z*mod;
	return (ans+mod)%mod;
}

ll crt (int *a,int *m,int n)
{
	ll M=1,ans=0;
	for (int i=1;i<=n;++i)	M*=m[i];
	for (int i=1;i<=n;++i){
		ll ni,jk;
		ex_gcd(M/m[i],m[i],ni,jk);//ni 逆元
		ans=(ans+mul(mul(M/m[i],a[i],M),ni,M))%M;
	}
	return ans;
}


扩展中国剩余定理(EXCRT)

目的

求最小的正整数 x x x,使其满足

{ x ≡ a 1 ( m o d   m ) x ≡ a 2 ( m o d   m 2 ) ⋮ x ≡ a n ( m o d   m n ) \begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases} xa1(mod m)xa2(mod m2)xan(mod mn)

其中 m 1 , m 2 … m n m_1,m_2\dots m_n m1,m2mn不一定互质

解法

对于 C R T CRT CRT而言,这里的条件变为 m m m之间可以不互质了
显然是不能向原来那样直接求了
考虑已经知道了前 i − 1 i-1 i1个方程的答案 x x x
设前 i − 1 i-1 i1 m m m的最小公倍数 l c m ( m 1 , m 2 … m i − 1 ) = M lcm(m1,m2\dots m_{i-1})=M lcm(m1,m2mi1)=M
现在考虑第 i i i个方程
x ≡ a i ( m o d   m i ) x\equiv a_i\left(mod\ m_i\right) xai(mod mi)
我们知道前 i − 1 i-1 i1个方程的最小解为 x x x,那么其通用解就是 x + k M x+kM x+kM
因为 k M kM kM对前 i − 1 i-1 i1 m m m取模肯定是等于 0 0 0
那么考虑了第 i i i个方程后的解应也是如上的一个形式
就设为 x + k M x+kM x+kM
那么我们就是要求关于 k k k的这样的方程
k M + x ≡ a i ( m o d   m i ) kM+x\equiv a_i\left(mod\ m_i\right) kM+xai(mod mi)
其中 x , a i , m i x,a_i,m_i x,ai,mi都是已知的
这就是一个简单的同余方程了
k M − p m i = a i − x kM-pm_i=a_i-x kMpmi=aix
其中两个未知数 k , p k,p k,p
e x _ g c d ex\_gcd ex_gcd求解即可
无解条件就是上述方程无解

code

#define ll long long
#define ull unsigned long long

ll ex_gcd (ll a,ll b,ll &x,ll &y)
{
	if (!b){	x=1,y=0;return a;}
	ll g=ex_gcd(b,a%b,x,y);
	int tmp=x;
	x=y,y=tmp-a/b*y;
	return g;
}

ll mul (ll a,ll b,ll mod)//快速乘
{
	a%=mod,b%=mod;
	ll c=(long double)a*b/mod;
	ll ans=(ull)a*b-(ull)c*mod;
	return (ans+mod)%mod;
}

ll ex_crt (ll *a,ll *m,int n)
{
	ll ans=a[1]%m[1],M=m[1];
	for (int i=2;i<=n;++i){
		ll gcd,x,y,c=(a[i]%m[i]-ans%m[i]+m[i])%m[i];
		gcd=ex_gcd(M,m[i],x,y);
		if (c%gcd)	return -1;
		x=mul(x,c/gcd,m[i]/gcd);
		ll lm=M;
		M=M/gcd*m[i];
		ans=((ans+mul(x,lm,M)%M)%M+M)%M;
	}
	return ans;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

你可能感兴趣的:(理解,数论,竞赛算法)