拓展中国剩余定理(exCRT)
前置知识:拓展欧几里得算法
可以发现一个问题:exCRT 的前置知识不包括 CRT,那是因为,这两者关系不大。
exCRT 与 CRT 一样,可以求解这样的同余方程组:
但是 exCRT 不需要 两两互质这个前提条件。
它的思想是数学归纳法,具体方法是这样的:
方法
如果只有一个方程,那么 。
如果不止一个方程:
假设已经求出了前 个方程的一个解 。
记 为 ,则 是前 个方程的通解。
求出一个整数 ,使得 ,若有解,则 就是前 个方程的一个解。
应该怎么求呢?
我们把它变一下形:
设 ,则 。
现在,如果 不成立,那么无解;否则,用拓欧求出 ,再将 和 都乘上 即可。
代码实现:
注意:exCRT 非常容易爆 long long
!
#include <algorithm>
#include <cstdio>
#include <cmath>
#define ll __int128
using namespace std;
ll gcd(ll a, ll b){
if (!b) return a;
return gcd(b, a % b);
}
inline ll lcm(ll a, ll b){
return a * b / gcd(a, b);
}
ll exgcd(ll a, ll b, ll& x, ll& y){
if (!b){
x = 1, y = 0;
return a;
}
ll ret = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - (a / b) * y;
return ret;
}
int n;
ll a[100001], b[100001], A, ans, d, m, k, x, y;
int main(){
scanf("%d", &n);
for (int i = 1;i <= n;i ++) scanf("%lld%lld", &b[i], &a[i]);
ans = a[1];
m = b[1];
for (int i = 2;i <= n;i ++){
A = ((a[i] - ans) % b[i] + b[i]) % b[i];
d = exgcd(m, b[i], x, y);
if (A % d != 0){
printf("-1");
return 0;
}
k = x * (A / d) % b[i];
ans += k * m;
m = lcm(m, b[i]);
ans = (ans % m + m) % m;
}
printf("%lld", (long long)ans);
}