{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) \begin{cases}x \equiv a_1 \pmod{m_1} \\x \equiv a_2 \pmod{m_2} \end{cases} {x≡a1(modm1)x≡a2(modm2)
{ x = a 1 + k 1 m 1 x = a 2 + k 2 m 2 \begin{cases}x=a_1+k_1m_1 \\x=a_2+k_2m_2 \end{cases} {x=a1+k1m1x=a2+k2m2
k 1 m 1 + ( − k 2 ) m 2 = a 2 − a 1 k_1m_1+(-k_2)m_2=a_2-a_1 k1m1+(−k2)m2=a2−a1
设 d = gcd ( m 1 , m 2 ) , e = a 2 − a 1 d=\gcd(m_1,m_2), e=a_2-a_1 d=gcd(m1,m2),e=a2−a1
使用扩展欧几里得算法求解 x , y x,y x,y ,满足 x m 1 + y m 2 = d xm_1+ym_2=d xm1+ym2=d
则有 x ⋅ e d ⋅ m 1 + y ⋅ e d ⋅ m 2 = d ⋅ e d x \cdot \frac{e}{d} \cdot m_1+y \cdot \frac{e}{d} \cdot m_2=d \cdot \frac{e}{d} x⋅de⋅m1+y⋅de⋅m2=d⋅de
对比可得 { k 1 = x ⋅ e d k 2 = − y ⋅ e d \begin{cases}k_1=x \cdot \frac{e}{d} \\k_2=-y \cdot \frac{e}{d} \end{cases} {k1=x⋅dek2=−y⋅de
实际上有多组解 { k 1 = x ⋅ e d + m 2 d ⋅ n k 2 = − y ⋅ e d − m 1 d ⋅ n , n ∈ Z \begin{cases}k_1=x \cdot \frac{e}{d}+\frac{m_2}{d} \cdot n \\k_2=-y \cdot \frac{e}{d}-\frac{m_1}{d} \cdot n\end{cases} , n\in \mathbb{Z} {k1=x⋅de+dm2⋅nk2=−y⋅de−dm1⋅n,n∈Z
取 k 1 k_1 k1 的最小整数解, { A = a 1 + k 1 m 1 M = l c m ( m 1 , m 2 ) = m 1 m 2 d \begin{cases}A=a_1+k_1m_1 \\M=lcm(m_1,m_2)=\frac{m_1m_2}{d} \end{cases} {A=a1+k1m1M=lcm(m1,m2)=dm1m2
合并成了 x ≡ A ( m o d M ) x\equiv A \pmod{M} x≡A(modM)
对于有些题目,中间运算结果会爆long long。不要偷懒使用__int128,下面是错误示范 ,乖乖打龟速乘。(也不要手写__int128)
#include
#include
using namespace std;
typedef long long LL;
LL a[100005],m[100005];
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;
}
inline void excrt() {
LL M=1,A=0;
for (int i=1;i<=n;i++) {
LL x,y,d=exgcd(M,m[i],x,y),mm=m[i]/d;
if ((a[i]-A)%d) {puts("No solution!");return;}
x=(x%mm+mm)%mm;
LL k=(LL)((__int128)(a[i]-A)/d*x%mm+mm)%mm;
LL nM=M*mm;
A=(LL)((A+(__int128)k*M)%nM);
M=nM;
}
printf("%lld",A);
}
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld %lld",&m[i],&a[i]);
excrt();
return 0;
}