题目给定
x三 mi (mod ai),求一个最小的非负整数 x
即
x 三 m1 (mod a1)
x三 m2 (mod a2)
…
x三 mk (mod ak)
对于线性同余方程组,可以用中国剩余定理来解,但是要求m1,m2,…,mk两两互质
所以此题不能用中国剩余定理!
先解第1、2个式子
a1 * k1 + m1 = x
a2 * k2 + m2 = x
联立得:a1 * k1 - a2 * k2 = m2 - m1 (1)
可以利用exgcd解方程 a1 * k1 - a2 * k2 = gcd(a1, a2) = d,
求出来d
之后,判断 (m2 - m1) 是否是 d的整数倍,如果不是则无解!!!
如果是,则对于上式子解出来的 k1 *= b (令 b = (m2 - m1) / d),
此时 k1、k2 的通解是
k1’ = k1 + k * (a2 / d)
k2’ = k2 + k * (a1 / d)
(因为等式左边第一项的系数是正的,第二项的系数是负的,所以此处是的k2’也是加)
证明:k1’和k2’也满足(1)式
a1 * k1’ - a2 * k2’ = m2 - m1 (2)
= a1 * (k1 + k * (a2 / d)) - a2 * (k2 + k * (a1 / d))
==> a1 * k1 + k * (a2 * a1 /d) - a2 * k2 - k * (a2 * a1 / d)
= a1 * k1 - a2 * k2 = m2 -m1,
所以(1) == (2)
k1’ = k1 + k * (a2 / d)
<==> k1’ 三 k1 (mod a2 / d)
所以所有的k1’
(包括当前k1
)
都对a2 / d
同余
且所有的k1’
都满足 (1) 式,
设 b = abs(a2 / d)
所以 k1’ = (k1 % b + b) % b 是最小的非负整数解。
将 k1 = k1 + k (a2 / d) 带入 x = a1 * k1 + m1
==> x = a1 * (k1 + k (a2 / d)) + m1
= a1 * k1 + k * (a2 * a1 / d) + m1
= (a1 * k1 + m1) + k * lcm(a1, a2) (此时的a1,k1, lcm(a1, a2), m1都是求出来的)
x = m + k * a (可以将上式看成此种形式),这样就可以与
x = m3 + k3 * a3 进行联立求解,然后一直递归下去,
直到和最后一个式子 x = mk + k * ak 联立
求出来最终的
x = m + k * a
相当于 x 三 m (mod a),(m、x对a同余,即x、a在mod a 的意义下相同)
所以要求的最小的非负的x
:
x = (m % a + a) % a
AC code
using namespace std;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y){
if(!b){
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main(){
int t;
cin >> t;
ll a1, m1, a2, m2, k1, k2;
cin >> a1 >> m1;
bool flag = false;
for(int i = 0; i < t - 1; i++){
cin >> a2 >> m2;
// 求出 gcd(a1, a2) 和 k1, k2 的一组解
ll d = exgcd(a1, a2, k1, k2);
// 无解的情况
if((m2 - m1) % d){
flag = true;
break;
}
// 相当于对 a1 * k1 + a2 * k2 = d 等式两边同乘 (m2 - m1) / d
k1 *= (m2 - m1) / d;
ll b = abs(a2 / d);
// 求得k1的最小的非负整数解
k1 = (k1 % b + b) % b;
// 对 m1, a1 进行替换迭代求解
m1 = a1 * k1 + m1;
a1 = abs(a1 * a2 / d); // 保证 a1 非负
}
if(flag) puts("-1");
else printf("%lld\n", (m1 % a1 + a1) % a1);
return 0;
}