浅谈扩展中国剩余定理

扩展中国剩余定理(EXCRT)

顾名思义就是把中国剩余定理给扩展了废话,听着感觉很\(NB\)但实际上不难理解(狗头)

\(\begin{cases}x\equiv a_1 (\mod m_1)\\x\equiv a_2(\mod m_2)\\……\\x\equiv a_k(\mod m_k)\end{cases}\)

\(m_1,m_2……m_k\)两两不互质

设前\(k-1\)个方程组成的同余方程组的一个解是\(x\)

\(M=\prod\limits_{i=1}^{k-1}m_i\)

则由中国剩余定理可得通解为\(x+i*M(i\in\Z)\)

则加入第\(k\)个方程组后

我们其实就是要求\(t\in\Z\),使得

\(x+t*M\equiv a_k(\mod m_k)\)

将式子变形得

\(t*M\equiv a_k-x(\mod m_k)\)

其中\(M,a_k,x\)均为已知量

则式子可以看成\(at\equiv b(\mod m_k)\)

可以用exgcd求解\(t\)

如果该同余式无解,则原方程组无解

否则前\(k\)个同余式构成的方程组的一个解即为\(x_k=x+t*M\)

\(M\)需随求解过程更新

简单地用人话来说就是

进行\(k\)次扩展欧几里得

例题

/*
@ author:pyyyyyy
-----思路------
下面的代码,ai和bi表示的比较混乱,建议自行百度一个看看
-----debug-------

*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+2020;
int n,ai[N],bi[N];
int mul(int a,int b,int mod)
{
	int ret=0;
	while(b)
	{
		if(b&1) ret=(ret+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return ret;
}
int exgcd(int a,int b,int &x,int &y)
{
	if(b==0){
		x=1;y=0;return a;
	}
	int g=exgcd(b,a%b,x,y);
	int z=x;x=y;y=z-y*(a/b);
	return g; 
}
int excrt()
{
	int x,y,k;
	int M=ai[1],ans=bi[1];//构造出第一个同余方程的解
	for(int i=2;i<=n;++i)
	{
		int a=M,b=ai[i],c=(bi[i]-ans%b+b)%b;//ax≡c(mod b)
		int gcd=exgcd(a,b,x,y),lcm=b/gcd;//lcm是用来防止溢出的
		if(c%gcd!=0) return -1;//无解的特判 
		x=mul(x,c/gcd,lcm);
		ans+=x*M;
		M*=lcm;	
		ans=(ans%M+M)%M;
	} 
	return (ans%M+M)%M;
}
signed main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;++i)
		scanf("%lld %lld",&ai[i],&bi[i]);
	cout<<excrt();	
	return 0;
}
posted @ 2020-04-19 08:18  pyyyyyy  阅读(187)  评论(5编辑  收藏  举报