【数论】中国剩余定理
求如下方程组的解:
\[\begin{cases}
n \equiv r_1 \pmod {m_1} \\
n \equiv r_2 \pmod {m_2} \\
\dots \dots \\n
\equiv r_k \pmod {m_k}
\end{cases}
\]
我们把它拆成 \(k\) 个同样的同余方程组:
\[\begin{cases}
C_1 \equiv r_1 \pmod {m_1} \\
C_1 \equiv 0 \pmod {m_2} \\
\dots \dots \\
C_1\equiv 0 \pmod {m_k}
\end{cases}
\begin{cases}
C_2 \equiv 0 \pmod {m_1} \\
C_2 \equiv r_2 \pmod {m_2} \\
\dots \dots \\
C_2 \equiv 0 \pmod {m_k}
\end{cases}
\cdots
\begin{cases}
C_k \equiv 0 \pmod {m_1} \\
C_k \equiv 0 \pmod {m_2} \\
\dots \dots \\
C_k \equiv r_k \pmod {m_k}
\end{cases}
\]
设
\[M = \prod\limits_{i = 1}^{k}{m_i}
\]
\[C_i = r_i \times \frac{M}{m_i} \times (\frac{M}{m_1})^{-1}
\]
由同余的可加性,得:
\[n = \sum\limits_{i = 1}^{k}{C_i}
\]
其中 \((\frac{M}{m_i})^{-1}\) 表示 \(\frac{M}{m_i}\) 表示其在模 \(m_i\) 下的 逆元。
对于正确性证明,分别考虑每一个 \(i\),因为 \(n\) 含有因子 \(\frac{M}{m_i}\),所以 \(\frac{M}{m_i} \mid C_k\),即 满足除 \(C_k \equiv r_i \pmod{m_i}\) 以外的所有同余方程。因为 \(\frac{M}{m_i}\) 与 \((\frac{M}{m_i})^{-1}\) 互为逆元,所以:
\[\begin{aligned}
\frac{M}{m_i} \times (\frac{M}{m_i})^{-1} \equiv 1 \pmod {m_i} \\
r_i \times \frac{M}{m_i} \times (\frac{M}{m_i})^{-1} \equiv r_i \pmod {m_i} \\
C_i \equiv r_i \pmod{m_i}
\end{aligned}
\]
我们构造的每个 \(C_i\) 也就可以使第 \(i\) 个方程组成立。
#include <bits/stdc++.h>
#define int __int128
using namespace std;
const int N = 15;
int n;
int m[N], r[N];
inline void read(int& x){
int s = 0, w = 1;
char ch = getchar();
while(!isdigit(ch))
w = -1, getchar();
while(isdigit(ch))
s = s * 10 + ch - '0', ch = getchar();
x = s * w;
return;
}
inline void write(int x){
if(x < 0)
putchar('-'), x = -x;
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
inline int exgcd(int a, int b, int& x, int& y){
if(b == 0){
x = 1, y = 0;
return a;
}
int res = exgcd(b, a % b, x, y), t = x;
x = y, y = t - a / b * y;
return res;
}
inline int inv(int a, int p){
int res, x, y;
exgcd(a, p, x, y);
return (x % p + p) % p;
}
inline int crt(int n, int m[], int r[]){
int M = 1, s = 0;
for(int i = 1; i <= n; i++)
M *= m[i];
for(int i = 1; i <= n; i++)
s = (s + r[i] * (M / m[i]) * inv(M / m[i], m[i]) % M) % M;
s = (s + M) % M;
return s;
}
signed main(){
read(n);
for(int i = 1; i <= n; i++)
read(m[i]), read(r[i]);
write(crt(n, m, r));
return 0;
}