在大致理解解法的基础上进行归纳总结
/*
扩展中国剩余定理 EXCRT
x ≡ m1 (mod a1), x ≡ m2 (mod a2)
=> x = k1 * a1 + m1 = k2 * a2 + m2 (qwq)
=> a1 * k1 - a2 * k2 = m2 - m1
=> exgcd得特解k1 = x0, k2 = y0
(有解的条件是 d | m2 - m1)
=> 通解为k1 = x0 + k * a2 / d
k2 = y0 + k * a1 / d (d = gcd(a1, a2))
=> 代入(qwq)式得 x = (x0 + k * a2 / d) * a1 + m1
=> x = k * a1 * a2 / d + m1 + x0 * a1
= k * lcm(a1, a2) + (m1 + x0 * a1)
= k * A + M
=> x ≡ M (mod A)
1 * x + A * y = M
gcd(1, A) = 1;
A / gcd(1, A) = A
求x的最小非负整数解:(x % A + A) % A
*/
#include<iostream>
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 N;
ll X, M1, A1, M2, A2, K1, K2;
cin>>N>>A1>>M1;
for (int i = 2 ; i <= N ; i++){
cin>>A2>>M2;
ll D = exgcd(A1, -A2, K1, K2);
if ((M2 - M1) % D) return puts("-1") & 0;
K1 *= (M2 - M1) / D;
K1 = (K1 % (A2 / D) + (A2 / D)) % (A2 / D);
if (i == N) X = K1 * A1 + M1;
M1 = M1 + K1 * A1;
A1 = A1 * A2 / D;
}
A1 = abs(A1);
cout<<(X % A1 + A1) % A1;
}
另一种写法:
将a1 * k1 + (-a2) * k2 = m2 - m1换成a1 * k1 + a2 * (-k2) = m2 - m1
即exgcd(A1, A2, K1, K2),保证D为正整数(若有负数-A2,D可能为负)
从而保证A2 / D为正整数,取模后K1为最小非负整数解
又由于Ai > Mi,所以最小非负整数解K1求得的X即为最小非负整数解X
int main(){
int N;
ll X, M1, A1, M2, A2, K1, K2;
cin>>N>>A1>>M1;
for (int i = 2 ; i <= N ; i++){
cin>>A2>>M2;
ll D = exgcd(A1, A2, K1, K2);
if ((M2 - M1) % D) return puts("-1") & 0;
K1 *= (M2 - M1) / D;
K1 = (K1 % (A2 / D) + (A2 / D)) % (A2 / D);
if (i == N) X = K1 * A1 + M1;
M1 = M1 + K1 * A1;
A1 = A1 * A2 / D;
}
cout<<X;
}
安利一下算法基础课&提高课 笔记要点 + OIer必备小知识