中国剩余定理及其拓展

中国剩余定理

求下列同余方程组的解(保证 n i , n j n_i,n_j ni,nj两两互质):

x ≡ a 1 ( m o d    n 1 ) x≡a_1(\mod n_1) xa1(modn1)
x ≡ a 2 ( m o d    n 2 ) x≡a_2(\mod n_2) xa2(modn2)
x ≡ a 3 ( m o d    n 3 ) x≡a_3(\mod n_3) xa3(modn3)

x ≡ a k ( m o d    n k ) x≡a_k(\mod n_k) xak(modnk)

唯一解: a n s ≡ ∑ a i ∗ c i ( m o d    M ) ans≡\sum a_i*c_i(\mod M) ansaici(modM),其中 M = ∏ n i , m i = M / n i , m i − 1 M=\prod n_i,m_i=M/n_i,m_i^{-1} M=ni,mi=M/ni,mi1 m i m_i mi n i n_i ni意义下的逆元, c i = m i ∗ m i − 1 c_i=m_i*m_i^{-1} ci=mimi1(不对n_i取模)。

证明:

  1. i ≠ j i≠j i=j时,因为 m i = M / n i m_i=M/n_i mi=M/ni,所以 m i m o d    n j = 0 m_i \mod n_j=0 mimodnj=0,即 c i ≡ m i ≡ 0 ( m o d    n j ) c_i≡m_i≡0(\mod n_j) cimi0(modnj)
  2. a n s ≡ ∑ j = 1 k a j ∗ c j ( m o d    n i ) ans≡\sum_{j=1}^k a_j*c_j(\mod n_i) ansj=1kajcj(modni)
  3. a n s ≡ a i ∗ c i ( m o d    n i ) ans≡a_i*c_i(\mod n_i) ansaici(modni)
  4. 因为 c i = m i ∗ m i − 1 c_i=m_i*m_i^{-1} ci=mimi1,所以 c i ≡ 1 ( m o d    n i ) c_i≡1(\mod n_i) ci1(modni)
  5. a n s ≡ a i ( m o d    n i ) ans≡a_i(\mod n_i) ansai(modni)

代码:

int a[N],b[N],m[N],c[N];
void exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x = 1;
		y = 0;
		return ;
	}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
}

int crt(int n)
{
	int mul = 1,res = 0;
	for(int i=1;i<=n;i++)
		mul *= a[i];
	for(int i=1;i<=n;i++)
		m[i] = mul/a[i];
	for(int i=1;i<=n;i++)
	{
		int x,y;
		exgcd(m[i],a[i],x,y);
		c[i] = m[i]*x;
		res = (res + b[i]*c[i])%mul;
	}
	return (res+mul)%mul;
}
signed main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	cout<<crt(n)<<endl;
	return 0;
}

拓展中国剩余定理:

求下列同余方程组的解(不保证 n i , n j n_i,n_j ni,nj两两互质):

x ≡ a 1 ( m o d    n 1 ) x≡a_1(\mod n_1) xa1(modn1)
x ≡ a 2 ( m o d    n 2 ) x≡a_2(\mod n_2) xa2(modn2)
x ≡ a 3 ( m o d    n 3 ) x≡a_3(\mod n_3) xa3(modn3)

x ≡ a k ( m o d    n k ) x≡a_k(\mod n_k) xak(modnk)

先看前两个方程:

  1. x = k 1 ∗ n 1 + a 1 = k 2 ∗ n 2 + a 2 x=k_1*n_1+a_1=k_2*n_2+a_2 x=k1n1+a1=k2n2+a2
  2. a 2 − a 1 = k 1 ∗ n 1 − k 2 ∗ n 2 a_2-a_1=k_1*n_1-k_2*n_2 a2a1=k1n1k2n2
  3. ( a 2 − a 1 ) m o d    g c d ( n 1 , n 2 ) ≠ 0 (a_2-a_1) \mod gcd(n_1,n_2)≠0 (a2a1)modgcd(n1,n2)=0时无解
  4. 有解时,通过exgcd算法求出 k 1 , k 2 k_1,k_2 k1,k2的一组解
  5. 回代 k 1 k_1 k1,即有 x ≡ k 1 ∗ n 1 + a 1 ( m o d    l c m ( n 1 , n 2 ) ) x≡k_1*n_1+a_1(\mod lcm(n_1,n_2)) xk1n1+a1(modlcm(n1,n2))
  6. 多次求解,合并

代码:

int a[N],b[N];
void exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x = 1;
		y = 0;
		return ;
	}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
}
int qmul(ll a,ll b,ll p)
{
	ll res = 0;
	while(b)
	{
		if(b&1)
			res = (res + a) % p;
		a = (a+a)%p;
		b>>=1;
	}
	return res;
}
signed main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	int ans = b[1],M = a[1];
	for(int i=2;i<=n;i++)
	{
		int x,y;
		int c = ((b[i]-ans)%a[i]+a[i])%a[i];
		exgcd(M,a[i],x,y);
		int d = __gcd(M,a[i]);
		x = qmul(x,c/d,a[i]);
		ans+=M*x;
		M*=a[i]/d;
		ans = (ans+M)%M;
	}
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值