基础知识
拉格朗日定理 :在模 p p p 意义下,最高次项系数非 0 0 0 的 n n n 次多项式至多有 n n n 个根。
线性同余方程组
可以使用 CRT 解决模数互质的情况,exCRT 解决模数不互质的情况。
{ x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) ⋯ x ≡ a 3 ( m o d m 3 ) \begin{cases}
x\equiv a_1 \pmod {m_1}\\
x\equiv a_2 \pmod {m_2}\\
\cdots\\
x\equiv a_3 \pmod {m_3}\\
\end{cases}
⎩ ⎨ ⎧ x ≡ a 1 ( mod m 1 ) x ≡ a 2 ( mod m 2 ) ⋯ x ≡ a 3 ( mod m 3 )
模数互质
设 M = ∏ i = 1 n m i , M i = m ÷ m i M=\prod_{i=1}^{n}m_i,M_i=m\div m_i M = ∏ i = 1 n m i , M i = m ÷ m i ,t i t_i t i 是线性同余方程 M i t i ≡ 1 ( m o d m i ) M_it_i\equiv 1 \pmod{m_i} M i t i ≡ 1 ( mod m i ) 的一个解,也就是说 t i t_i t i 是 M i M_i M i 模 m i m_i m i 的逆元(显然 M i ⊥ m i M_i \perp m_i M i ⊥ m i 当且仅当 m i m_i m i 两两互质),那么 x = ∑ i = 1 n a i M i t i + k M x=\sum_{i=1}^{n}a_iM_it_i + kM x = ∑ i = 1 n a i M i t i + k M ,最小非负整数解需要求 ∑ i = 1 n a i M i t i m o d M \sum_{i=1}^{n}a_iM_it_i\bmod M ∑ i = 1 n a i M i t i mod M 。
1 2 3 4 5 6 7 8 9 10 i64 CRT (void ) { i64 ans = 0 , x; for (int i = 1 ; i <= n; ++i) { M[i] = mm / m[i]; t[i] = inv (M[i], m[i]); ans = (ans + a[i] * M[i] * t[i]) % mm; } return (ans % mm + mm) % mm; }
模数不互质
考虑如何合并两个方程组。我们先假定一定可以合并,然后看看什么时候合并之后的解是 ∅ \varnothing ∅ 。
假设我们有:
{ x ≡ a ( m o d A ) x ≡ b ( m o d B ) \begin{cases}
x\equiv a \pmod A\\
x\equiv b \pmod B
\end{cases}
{ x ≡ a ( mod A ) x ≡ b ( mod B )
那么 x = A k 1 + a = B k 2 + b x=Ak_1+a=Bk_2+b x = A k 1 + a = B k 2 + b ,不难使用 exgcd 求出一组合法的 k 1 , k 2 k_1,k_2 k 1 , k 2 ,则通解为:
K 1 = k 1 + t × B gcd ( A , B ) K 2 = k 2 − t × A gcd ( A , B ) K_1=k_1+t\times \frac{B}{\gcd(A,B)}\\
K_2=k_2-t\times \frac{A}{\gcd(A,B)}
K 1 = k 1 + t × g cd( A , B ) B K 2 = k 2 − t × g cd( A , B ) A
则 x = A ( k 1 + t × B gcd ( A , B ) ) + a = A k 1 + t × lcm ( A , B ) + a x=A(k_1+t\times \frac{B}{\gcd(A,B)})+a=Ak_1+t\times \operatorname{lcm}(A,B)+a x = A ( k 1 + t × g c d ( A , B ) B ) + a = A k 1 + t × lcm ( A , B ) + a ,也就是:
x ≡ A k 1 + a ( m o d lcm ( A , B ) ) x\equiv Ak_1+a \pmod{\operatorname{lcm}(A,B)}
x ≡ A k 1 + a ( mod lcm ( A , B ))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 i64 exCRT (void ) { i64 A = 1 ; LL a = 0 ; for (int i = 1 ; i <= n; ++i) { i64 b = ::A[i], B = ::B[i], x, y, c = b - a; i64 g = exgcd (A, B, x, y); if (c % g != 0 ) return -1 ; a = A * ((LL)x * (c / g)) + a; A = A / g * B; a %= A; } return (a + A) % A; }