输入样例:
2
8 7
11 9
输出样例:
31
想法:
核心:让程序去执行合并的操作
先用扩展欧几里得算法求得k,然后代入到原式内,此时扩展欧几里得算法求得的结果与原式成整数倍,所以求得的解需要 * (m2-m1)/d
x (mod a1) = m1 (mod a1)
x (mod a2) = m2 (mod a2)
x (mod a3) = m3 (mod a3)
·
·
·
x (mod an) = mn (mod an)
将等式两两合并成一个式子,直到最后只剩下一个式子
合并过程:
x mod a1 = m1 => x = a1k1 + m1 ①
x mod a2 = m2 => x = a2k2 + m2 ②
合并消去x : k1 * a1 - k2 * a2 = m2 - m1 ③
此时将 k1 k2当作x,y ; a1 a2 当作a,b;
转换为式子 : ax+by = gcd(a,b);
有解条件为: m2-m1 = gcd(a,b) 的倍数 d= gcd(a,b)
解出k:
k1= k1+k(a2/d) = k1%(a2/d)
k2= k2+k(a1/d) = k2%(a1/d)
带入③式恒成立
将 k1= k1+k(a2/d) 代入①式
x = a1k1 + m1 = (k1+k(a2/d))*a1 + m1
化简后:
x = a1k1 + m1 +k (a2 * a1 /d) ④
目标: 求出m和a 获取到新的等式 x = m + ka
再化简 ( 等式右侧的值均已知 )
将 m= a1k1 + m1 ; a=(a2 * a1/d)
x = m + ka ⑤
再将⑤与下一个方程合并求解
最后 x = m+ka;
因为 m = ankn + mn 和 a = | a2 * a1/d |
此时 x = m+ka; 减去一个数的整数倍等于mod上这个数
所以结果为 x = (m%a + a)%a 防止是负数,所以加上a再 %a
求解得出x 的值
代码
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
int n;
LL exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL inline mod(LL a, LL b){
return ((a % b) + b) % b;
}
int main(){
scanf("%d", &n);
LL a1, m1;
scanf("%lld%lld", &a1, &m1);
for(int i = 1; i < n; i++){
LL a2, m2, k1, k2;
scanf("%lld%lld", &a2, &m2);
LL d = exgcd(a1, -a2, k1, k2);
if((m2 - m1) % d){ puts("-1"); return 0; }
k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d));
m1 = k1 * a1 + m1;
a1 = abs(a1 / d * a2);
}
printf("%lld\n", m1);
return 0;
}