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;
}

浙公网安备 33010602011771号