1. 中国剩余定理(CRT)
1.1 问题引入
{ x ≡ a 1 ( m o d p 1 ) x ≡ a 2 ( m o d p 2 ) … x ≡ a n ( m o d p n ) \begin{cases} x\equiv a_1 (mod~p_1) \\ x\equiv a_2 (mod~p_2) \\ ~~~~ ~ ~~ ~\dots \\ x\equiv a_n (mod~p_n) \\ \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1(mod p1)x≡a2(mod p2) …x≡an(mod pn)
1.2 方程组的解性
- 我们记 M = ∏ i = 1 n p i M=\prod_{i=1}^np_i M=∏i=1npi, m i = m p i m_i=\frac{m}{p_i} mi=pim。
- 我们假设已经得到一个解 x 0 x_0 x0,则 x 0 + k M ( k ∈ Z ) x_0+kM(k\in \mathbb Z) x0+kM(k∈Z) 显然都是方程组的解。
- 即所有的解构成关于 M M M 的一个剩余类。
- 因此我们只需要求出 [ 0 , M ) [0,M) [0,M) 中的整数解即可。
- 中国剩余定理给出结论,这个方程在 [ 0 , M ) [0,M) [0,M) 中存在唯一解。
1.3 方程组的解法
- 我们先考虑如何求出解。
- 我们考虑 n n n 个方程组,第 i i i 个方程组为
{ x i ≡ 0 ( m o d p 1 ) x i ≡ 0 ( m o d p 2 ) … x i ≡ a i ( m o d p i ) … x i ≡ 0 ( m o d p n − 1 ) x i ≡ 0 ( m o d p n ) \begin{cases} x_i\equiv 0 (mod~p_1) \\ x_i\equiv 0 (mod~p_2) \\ ~~~~ ~ ~~ ~\dots \\ x_i \equiv a_i (mod~p_i)\\ ~~~~~ ~~ ~ \dots \\ x_i\equiv 0 (mod~p_{n-1}) \\ x_i\equiv 0 (mod~p_n) \\ \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧xi≡0(mod p1)xi≡0(mod p2) …xi≡ai(mod pi) …xi≡0(mod pn−1)xi≡0(mod pn)
- 那么 ∑ i = 1 n x i \sum_{i=1}^nx_i ∑i=1nxi 就为一个解。
- 只需要对 M M M 取模即得到 [ 0 , n ) [0,n) [0,n) 内的特解。
- 考虑 x i x_i xi 怎么求。
- 我们再考虑一个方程组
{ y i ≡ 0 ( m o d p 1 ) y i ≡ 0 ( m o d p 2 ) … y i ≡ 1 ( m o d p i ) … y i ≡ 0 ( m o d p n − 1 ) y i ≡ 0 ( m o d p n ) \begin{cases} y_i\equiv 0 (mod~p_1) \\ y_i\equiv 0 (mod~p_2) \\ ~~~~ ~ ~~ ~\dots \\ y_i \equiv 1 (mod~p_i)\\ ~~~~~ ~~ ~ \dots \\ y_i\equiv 0 (mod~p_{n-1}) \\ y_i\equiv 0 (mod~p_n) \\ \end{cases} ⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧yi≡0(mod p1)yi≡0(mod p2) …yi≡1(mod pi) …yi≡0(mod pn−1)yi≡0(mod pn)
- 那么我们可以令 x i = a i y i x_i=a_iy_i xi=aiyi。
- 因为 p j ∣ y i ( j ≠ i ) p_j|y_i(j\neq i) pj∣yi(j̸=i),而 p i p_i pi 之间两两互质,所以 m i m_i mi 在模 p i p_i pi 意义下存在逆元,所以我们可以直接令 y i = m i × m i − 1 y_i=m_i\times m_i^{-1} yi=mi×mi−1, m i − 1 m_i^{-1} mi−1 表示逆元。
- 逆元可以视情况用 e x g c d exgcd exgcd 或者费马小定理求。
- 所以 x i = m i × m i − 1 × a i x_i=m_i\times m_i^{-1}\times a_i xi=mi×mi−1×ai。
- 所以 a n s = ∑ i = 1 n m i × m i − 1 × a i ans=\sum_{i=1}^nm_i\times m_i^{-1}\times a_i ans=∑i=1nmi×mi−1×ai,为了防止溢出,我们只需要在模 M M M 意义下做运算即可。
- 注意在 C R T CRT CRT 和 e x C R T exCRT exCRT 中,有时乘法运算可能会溢出,关于如何处理这类问题参见 【小技巧】O(1)快速乘 - changle_cyx。
1.4 解在模 M M M 意义下唯一
- 接下来我们证明这个解在模 M M M 意义下唯一。
- 即证明不存在两个解 x 0 , x 1 x_0,x_1 x0,x1, 使得 M ∤ x 1 − x 0 M\nmid x_1-x_0 M∤x1−x0。
- 反证法:
- 令 x 0 x_0 x0 表示原方程组的一个特解,存在另解 x 0 + d x_0+d x0+d,使得 M ∤ d M\nmid d M∤d。
- 则 ∃ i ∈ [ 1 , n ] , p i ∤ d \exist i\in [1,n],p_i\nmid d ∃i∈[1,n],pi∤d,即 d ̸ ≡ 0 ( m o d p i ) d\not \equiv 0(mod~p_i) d̸≡0(mod pi)。
- 由 x 0 x_0 x0 是原方程组的解可得 a n s 0 ≡ a i ( m o d p i ) ans_0\equiv a_i(mod~p_i) ans0≡ai(mod pi)。
- 所以 x 0 + d ̸ ≡ a i ( m o d p i ) x_0+d\not \equiv a_i(mod~p_i) x0+d̸≡ai(mod pi), x 0 + d x_0+d x0+d 不是原方程组的解,与假设矛盾。
- 证毕。
- 所以我们得到了中国剩余定理。
- 中国剩余定理中的这个唯一性应用广泛,在第3部分中举两个例子说明。
2. 扩展中国剩余定理(exCRT)
2.1 问题引入
- 中国剩余定理求解的是模数两两互质的方程组。
- 那么对于模数不满足两两互质的方程组该如何求解呢?
- 即求解
{ x ≡ a 1 ( m o d p 1 ) x ≡ a 2 ( m o d p 2 ) … x ≡ a n ( m o d p n ) \begin{cases} x\equiv a_1 (mod~p_1) \\ x\equiv a_2 (mod~p_2) \\ ~~~~ ~ ~~ ~\dots \\ x\equiv a_n (mod~p_n) \\ \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡a1(mod p1)x≡a2(mod p2) …x≡an(mod pn)
- 其中 p i p_i pi 没有特殊约束。
2.2 方程组的解性
- 方程组不一定有解,我们可以在求解过程中顺便判断。
- 我们记 m i = l c m ( p 1 , p 2 , … , p i ) m_i=lcm(p_1,p_2,\dots,p_i) mi=lcm(p1,p2,…,pi), M = l c m ( p 1 , p 2 , … , p n ) M=lcm(p_1,p_2,\dots,p_n) M=lcm(p1,p2,…,pn)。
- 假设我们得到一个特解 x 0 x_0 x0,那么 x 0 + k M ( k ∈ Z ) x_0+kM(k\in \mathbb Z) x0+kM(k∈Z) 都是方程组的解。
- 解出来的 x x x 同样是一个剩余类。
- 类似1.4的证明,我们仍然可以得到若方程组有解,则方程组的解在模 M M M 意义下唯一。
2.3 方程组的解法
- 我们不能像互质的情况那样做的原因就是,因为不互质,所以我们需要的乘法逆元可能不存在。
- 我们考虑从前往后,一个一个方程地合并。
- 假设我们解到第 i i i 个方程,我们就令 x i x_i xi 表示模 m i m_i mi 意义下的唯一解。
- 对于第 1 1 1 个方程,我们直接令 x 1 = a 1 x_1=a_1 x1=a1。
- 对于第 i ( i > 1 ) i(i>1) i(i>1) 个方程,我们知道前 i − 1 i-1 i−1 个方程的 通解 为 x i − 1 + k m i − 1 ( k ∈ Z ) x_{i-1}+km_{i-1}(k\in \mathbb Z) xi−1+kmi−1(k∈Z)。
- 那么现在我们加上第 i i i 个方程的限制 x ≡ a i ( m o d p i ) x\equiv a_i(mod~p_i) x≡ai(mod pi)。
- 那么前 i i i 个方程联立后等价于方程
x i − 1 + k m i − 1 ≡ a i ( m o d p i ) x_{i-1}+km_{i-1}\equiv a_i(mod~p_i) xi−1+kmi−1≡ai(mod pi)
m i − 1 k + p i y = a i − x i − 1 m_{i-1}k+p_iy=a_i-x_{i-1} mi−1k+piy=ai−xi−1
- 然后用扩展欧几里得算法( e x g c d exgcd exgcd)解一下这个方程。
- 若存在某个 i i i,使得这个方程无解,即 ( m i − 1 , p i ) ∤ a i − x i − 1 (m_{i-1},p_i)\nmid a_i-x_{i-1} (mi−1,pi)∤ai−xi−1,意味着整个方程组也无解。
- 否则令解出的特解 k k k 取到模 p i ( m i − 1 , p i ) \frac{p_i}{(m_{i-1},p_i)} (mi−1,pi)pi 意义下的唯一解,即令 k k k 对 p i ( m i − 1 , p i ) \frac{p_i}{(m_{i-1},p_i)} (mi−1,pi)pi 取模。
- 然后得到 x i = x i − 1 + m i − 1 k x_i=x_{i-1}+m_{i-1}k xi=xi−1+mi−1k,然后也令 x i x_i xi 对 m i m_i mi 取模即可。
- 最后 x n x_n xn 即为答案。
- 模板题:洛谷P4777 - 扩展中国剩余定理(EXCRT)
#include
#include
#include
#include
#include
#include
#include
template <class T>
inline void read(T &x)
{
static char ch;
while (!isdigit(ch = getchar()));
x = ch - '0';
while (isdigit(ch = getchar()))
x = x * 10 + ch - '0';
}
typedef long long s64;
const int MaxN = 1e5 + 5;
int n;
s64 p[MaxN], a[MaxN], pre_lcm[MaxN];
inline s64 qmul(s64 b, s64 p, const s64 &mod)
{
b = (b % mod + mod) % mod;
p = (p % mod + mod) % mod;
s64 res = 0;
for (; p; p >>= 1, (b = b + b) > mod ? (b -= mod) : 0)
if (p & 1)
{
res = res + b;
if (res >= mod)
res -= mod;
}
return res;
}
inline s64 ex_gcd(const s64 &a, const s64 &b, s64 &x, s64 &y)
{
if (!b)
return x = 1, y = 0, a;
s64 res = ex_gcd(b, a % b, y, x);
y -= a / b * x;
return res;
}
inline s64 solve_equ(const s64 &a, const s64 &b, const s64 &c)
{
s64 x, y;
s64 d = ex_gcd(a, b, x, y);
return qmul(x, c / d, b / d);
}
int main()
{
read(n);
for (int i = 1; i <= n; ++i)
read(p[i]), read(a[i]);
pre_lcm[1] = p[1];
for (int i = 2; i <= n; ++i)
pre_lcm[i] = p[i] / std::__gcd(pre_lcm[i - 1], p[i]) * pre_lcm[i - 1];
s64 x = a[1];
for (int i = 2; i <= n; ++i)
{
s64 k = solve_equ(pre_lcm[i - 1], p[i], a[i] - x);
x = x + qmul(pre_lcm[i - 1], k, pre_lcm[i]);
if (x >= pre_lcm[i])
x -= pre_lcm[i];
}
std::cout << x << std::endl;
return 0;
}
3. 中国剩余定理的简单应用
- 我们举两个十分十分十分简单的例子(dalao勿d)。
3.1 欧拉函数是积性函数的证明
-
欧拉函数 φ ( n ) = ∑ i = 1 n [ i ⊥ n ] \varphi(n)=\sum_{i=1}^n[i\perp n] φ(n)=∑i=1n[i⊥n],即 1 1 1 到 n n n 中与 n n n 互质的数的个数。
-
欧拉函数是积性函数。
-
若 p ⊥ q p\perp q p⊥q,则 φ ( p q ) = φ ( p ) φ ( q ) \varphi(pq)=\varphi(p)\varphi(q) φ(pq)=φ(p)φ(q)。
-
下面从中国剩余定理的角度给出证明:
- 我们设 A A A 表示 1 1 1 到 p p p 中与 p p p 互质的数组成的集合, B B B 表示 1 1 1 到 q q q 中与 q q q 互质的数组成的集合, C C C 表示 1 1 1 到 p q pq pq 中与 p q pq pq 互质的数的集合。
- 因为 p ⊥ q p\perp q p⊥q,所以 i ⊥ p q ⇔ i ⊥ p 且 i ⊥ q i\perp pq\Leftrightarrow i\perp p且i\perp q i⊥pq⇔i⊥p且i⊥q。
- 根据辗转相减法,我们知道 ( n , m ) = ( n , m + k n ) , k ∈ Z (n,m)=(n,m+kn),k\in \mathbb Z (n,m)=(n,m+kn),k∈Z。
- 结合上述结论,我们可以得到
C = { x ∣ { x ≡ a ( m o d p ) x ≡ b ( m o d q ) , a ∈ A , b ∈ B } C=\{x|\begin{cases}x\equiv a(mod~p)\\ x\equiv b(mod~q)\end{cases},a\in A,b\in B\} C={x∣{x≡a(mod p)x≡b(mod q),a∈A,b∈B}
- 根据中国剩余定理,我们对于每个 a ∈ A , b ∈ B a\in A,b\in B a∈A,b∈B,我们都能得到同余方程组
{ x ≡ a ( m o d p ) x ≡ b ( m o d q ) \begin{cases}x\equiv a(mod~p)\\ x\equiv b(mod~q)\end{cases} {x≡a(mod p)x≡b(mod q)
- 的唯一解 x x x,并且显然在 [ 1 , p q ] [1,pq] [1,pq] 中,不会存在一个 x x x,使得 x x x 是两个不同的同余方程组的解。
- 因此我们可以在 A × B A\times B A×B(笛卡尔乘积)和 C C C 之间建立双射。
- 所以集合 C C C 的元素个数等于集合 A A A 和集合 B B B 的元素个数的乘积。
- 证毕。
3.2 求解特殊模数的数论题
- 这里举一道很经典的题目:BZOJ1951 [SDOI2010]古代猪文
- 题目大意:求 G ∑ d ∣ n C n d m o d    p ( p = 999911659 , n , G ≤ 1 0 9 ) G^{\sum_{d|n}C_{n}^{d}}\mod p(p=999911659,n,G\le10^9) G∑d∣nCndmodp(p=999911659,n,G≤109)。
- 我们知道 p p p 是质数。
- 大家肯定会问,大部分数论题模数不都是质数吗,这有啥特殊的??
- 但是你发现这个 G G G 的指数很大,不能直接求出精确值。
- 我们知道欧拉定理 a b ≡ a b % φ ( p ) ( m o d p ) , a ⊥ p a^b\equiv a^{b\%\varphi(p)}(mod~p),a\perp p ab≡ab%φ(p)(mod p),a⊥p。
- 当 p ∣ G p|G p∣G 时,答案为 0 0 0。
- 否则有 G ⊥ p G\perp p G⊥p,我们可以用欧拉定理解决。
- 也就是我们的指数只需要取 ∑ d ∣ n C n d m o d    φ ( p ) \sum_{d|n}C_{n}^{d}\mod \varphi(p) ∑d∣nCndmodφ(p),即 ∑ d ∣ n C n d m o d    999911658 \sum_{d|n}C_{n}^{d}\mod 999911658 ∑d∣nCndmod999911658。
- 现在问题是,我们如果直接用 L u c a s Lucas Lucas 定理求解,不满足模数是质数的条件。
有人说:我会扩展Lucas!! (但是作者还不会)
- 但是这题完全没有必要用什么扩展 L u c a s Lucas Lucas。
- 因为 999911658 = 2 × 3 × 4679 × 35617 999911658=2\times3\times4679\times35617 999911658=2×3×4679×35617,即这个数的每个质因子的次数都为 1 1 1。
- 所以我们发现我们只需要求出 ∑ d ∣ n C n d \sum_{d|n}C_{n}^{d} ∑d∣nCnd 对这四个数取模的结果后,用 C R T CRT CRT 合并即可( C R T CRT CRT 告诉我们,求出这四个答案,列出同余方程组,可以得到模 M M M 意义下的唯一解)。
- 然后就转化为模数为质数的问题,直接用 L u c a s Lucas Lucas 定理解决就好了。
- L u c a s Lucas Lucas 定理( p p p 为质数): ( n m ) = ( n / p m / p ) ( n % p m % p ) \binom{n}{m}=\binom{n/p}{m/p}\binom{n\%p}{m\% p} (mn)=(m/pn/p)(m%pn%p)。
#include
const int mod = 999911659;
const int p[5] = {0, 2, 3, 4679, 35617};
const int MaxN = 4e4 + 5;
int n, G;
int a[5], fac[MaxN], inv[MaxN];
inline void add(int &x, const int &y, const int &mod)
{
x += y;
x >= mod ? x -= mod : 0;
}
inline int qpow(int a, int b, const int &mod)
{
int res = 1;
for (; b; b >>= 1, a = 1LL * a * a % mod)
if (b & 1)
res = 1LL * res * a % mod;
return res;
}
inline int lucas(const int &n, const int &m, const int &mod)
{
if (n < m) return 0;
if (n < mod && m < mod) return 1LL * fac[n] * inv[m] % mod * inv[n - m] % mod;
return 1LL * lucas(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod) % mod;
}
inline int solve(const int &p)
{
fac[0] = 1;
for (int i = 1; i < p; ++i)
fac[i] = 1LL * fac[i - 1] * i % p;
inv[p - 1] = qpow(fac[p - 1], p - 2, p);
for (int i = p - 2; i >= 0; --i)
inv[i] = 1LL * inv[i + 1] * (i + 1) % p;
int res = 0;
for (int i = 1; i * i <= n; ++i)
if (n % i == 0)
{
add(res, lucas(n, i, p), p);
if (i * i != n)
add(res, lucas(n, n / i, p), p);
}
return res;
}
int main()
{
scanf("%d%d", &n, &G);
if (G == mod)
{
puts("0");
return 0;
}
for (int i = 1; i <= 4; ++i)
a[i] = solve(p[i]);
int lcm = mod - 1, ans = 0;
for (int i = 1; i <= 4; ++i)
{
int x = lcm / p[i];
add(ans, 1LL * x * qpow(x, p[i] - 2, p[i]) % lcm * a[i] % lcm, lcm);
}
printf("%d\n", qpow(G, ans, mod));
return 0;
}