拓展中国剩余定理(excrt)

匿名 (未验证) 提交于 2019-12-02 23:51:01

问题

求解同余方程组

其中各个方程的模数为不一定两两互质的整数, 求x的最小非负整数解

求解

假设已经求出前k-1个方程组成的同余方程组的一个解为x

且有M=lcm(mo[1],mo[2],mo[3],...,mo[k-1])

则前k-1个方程的方程组通解为

因为M为前面方程模数的最小公倍数,所以M可以整除任意一个模数,所以方程组加上或减去M对于方程的同余性没有影响。

那么对于加入第k个方程后的方程组

x+tM≡yu[k](mod mo[k])

tM≡yu[k]x(mo[k])

对于这个式子我们已经可以通过扩展欧几里得求解t

若该同余式无解,则整个方程组无解, 若有,则前k个同余式组成的方程组的一个解解为xk=x+t*M

所以整个算法的思路就是求解k次扩展欧几里得

洛谷 P4777

#include<bits/stdc++.h> using namespace std; #define ll __int128 ll ans,x,y,a,b,c,yu[100005],mo[100005],M,n; long long read()//int 128好像只能用快读 {     ll f=1,x=0;     char ss=getchar();     while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}     while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}     return f*x; } long long gcd(ll a,ll b) { 	ll c; 	while(a%b) 	{ 		c=a%b; 		a=b; 		b=c; 	} 	return b; } long long lcm(ll a,ll b) { 	return a/gcd(a,b)*b; } void exgcd(ll a,ll b) { 	if(b==0) 	{ 		x=1;y=0; 		return; 	} 	exgcd(b,a%b); 	ll tem=x; 	x=y; 	y=tem-a/b*y; } long long excrt() { 	M=mo[1];ans=yu[1];//特判第一个方程 	for(int i=2;i<=n;i++) 	{ 		exgcd(M,mo[i]);//求解方程 t*M+y*mo[i]=yu[i]-ans; 		ll gcdd=gcd(M,mo[i]); 		if((yu[i]-ans)%gcdd!=0)return -1;//如果(yu[i]-ans)不是gcd(M,mo[i])的倍数,则根据裴蜀定理,方程无解 		x*=(yu[i]-ans)/gcdd;//刚才求出的是方程 t*M+y*mo[i]==gcd(M,mo[i])的解,现在将方程解出的x,y同时扩大倍数,就成了方程真正的解。但y没有用,只是个比例系数,就不管了。 		ans=ans+x*M;//上面的解析有说,更新答案 		M=M/gcd(M,mo[i])*mo[i];//更新M的值 		ans=(ans%M+M)%M;//之前的答案只是一个肯定成立的解,现在把ans改成在当前余数系下的最小非负整数答案 	} 	return ans; } int main() {     n=read();     for(ll i=1;i<=n;i++)         mo[i]=read(),yu[i]=read();     cout<<excrt();     return 0; } 

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!