p4777 exCRT

P4777 【模板】扩展中国剩余定理(EXCRT)

链接:https://www.luogu.com.cn/problem/P4777

题目简述

给定 \(n\) 组非负整数 \(a_i, b_i\) ,求解关于 \(x\) 的方程组的最小非负整数解。

\[\begin{cases}x\equiv b_1\pmod{a_1}\\x\equiv b_2\pmod{a_2}\\\dots\\x\equiv b_n\pmod{a_n}\end{cases} \]

输入格式

输入第一行包含整数 \(n\)
接下来 \(n\) 行,每行两个非负整数 \(a_i, b_i\)

输出格式

输出一行,为满足条件的最小非负整数 \(x\)

解:

由于模数不互质,普通的CRT公式已经无法胜任,这里需要考虑其他解法,比如不断合并方程组,直到只剩下一个方程组就能解决这道题了
现在就来思考如何合并两个方程,考虑合并方程:

\[\begin{cases}x\equiv bb\pmod{aa}\\x\equiv b\pmod{a}\end{cases} \]

也就是说存在$$aaX+x=bb$$

\[aY+x=b \]

合并两式得:

\[aaX+aY=bb-b(这里本来是减号,变成加号只是解正负的问题) \]

这里容易看出这是一个标准的exgcd(扩展欧几里得),可以求出特解\(x_0\),\(y_0\)使得:

\[aax_0+ay_0=gcd(aa,a) \]

两边同时乘上\(\frac{bb-b}{gcd(aa,a)}\)得:

\[aa\frac{(bb-b)x_0}{gcd(aa,a)}+a\frac{(bb-b)y_0}{gcd(aa,a)}=bb-b \]

由此就得到了原方程的一对特解,我们可以从其得到通解:

\[X=x_0+\frac{a}{gcd(a,aa)}*k(k\in{Z}) \]

\[Y=y_0+\frac{aa}{gcd(a,aa)}*k(k\in{Z}) \]

将其代入\(aX+x=b\),得:

\[x+aa*(x_0+\frac{a}{gcd(aa,a)}*k)=bb \]

\[x=bb-aa*x_0-\frac{aa*a}{gcd(aa,a)}*k \]

这样我们就合并出了一个新的方程:

\[x\equiv{bb-aa*x_0}\pmod{lcm(aa,a}) \]

通过这个算法不断合并方程,最后就能解出答案了
代码:

#include<bits/stdc++.h>
#define int __int128
#define ll long long
using namespace std;
ll n,a,b,d;
int x,y;
int exgcd(int a,int b,int&x,int&y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int d=exgcd(b,a%b,x,y);
	int z=x;
	x=y;
	y=z-y*(a/b);
	return d;
}
signed main(){
	int aa=1,bb=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a>>b;
		d=exgcd(aa,a,x,y);
		x=(bb-b)/d*x;	
		bb=bb-aa*x;
		aa=a/d*aa;
		bb=(bb%aa+aa)%aa;
	}
	ll ans=(bb%aa+aa)%aa;
	cout<<ans;
	return 0;
}
posted @ 2025-08-28 17:30  Turkey_VII  阅读(10)  评论(0)    收藏  举报