求解:
M a1 (b1)
M a2 (b2)
M a3 (b3)
........
对于 上述式子我们可以拆成 :
M = b1 * p + a1 = b2 * q + a2
左右移项得到:
b1 * p - b2 * q = a2 - a1
可以发现 这就是一个同余方程:
a = b1 , b = b2 , x = p , y = q , c = a2 - a1
我们就可以用扩展欧几里得算法得到:
p 与 q 的特解 x , y。
同时 p 与 q 的通解也可以获得:p = x + (k * b) / gcd(a,b) ,q = y + (k * a) / gcd(a,b)
得到新的同余方程:
M = b1 * ( x + k * b / gcd(a,b)) + a1
将原来的 a = b1 , b = b2 , x = p , y = q , c = a2 - a1 。替换回来:
M = b1 * ( p + k * b2 / gcd(b1,b2) ) + a1
化简:因为:b1 * b2 /gcd(b1,b2) =lcm(b1,b2)
所以:M = k * lcm(b1,b2) + p * b1 + a1
得到:新的 a3 = p * b1 + a1 ,b3 = lcm(b1,b2) 。
这样合并 n - 1次即为答案。
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define int long long
const int N=5e4+100;
namespace crt{
int bi[N],ai[N]; //ai==a ,bi=m1;
int n;
int mul(int a, int b ,int p)
{
a%=p,b%=p;
int z = (long double) a / p * b;
int res = (unsigned long long) a * b - (unsigned long long) z * p;
return (res + p) % p;
}
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 - (a / b) * x;
return d;
}
int excrt()//拓展中国剩余定理
{
int x, y, k;
int M = bi[1], ans = ai[1];//第一个方程的特解
for(int i = 2; i <= n; ++ i) {
int a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;
int d = exgcd(a, b, x, y);
int bg = b / d;//lcm
if(c % d != 0) return 1e18; //判断是否无解,然而这题其实不用
x = mul(x, c / d, bg);//快速乘模板
ans += x * M;//更新前k个方程组的答案
M *= bg;//M为前k个m的lcm
ans = (ans % M + M) % M;
}
ans = (ans % M + M) % M;
//if(ans == 0) ans = M;//视情况而定,等于0的时候是因为给定的模数均为1,此时答案应该取任意值均可,而不是只有解 0 ,有时需要特判一下。
return ans;
}
};
void solve() {
int n;
cin >> n;
crt::n = n;
for (int i = 1; i <= n; i++) {
int x, y;
cin >> x >> y;
crt::bi[i] = x;
crt::ai[i] = y;
}
cout << crt::excrt() << '\n';
}
signed main() {
IOS;
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}