exgcd - crt gcd最大公约数(Hreatest Common Divisor)
欧几里得算法
gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a,b)=\gcd(b,a\mod b) g cd( a , b ) = g cd( b , a m o d b )
可以通过反证法证明
1 2 3 4 5 6 int gcd (int a, int b) { if (b == 0 ) return a; return gcd (b, a % b); }
exgcd用于接形如 a x + b y = gcd ( a , b ) ax+by=\gcd(a,b) a x + b y = g cd( a , b ) 的方程
a x + b y = gcd ( a , b ) 设 { a x 1 + b y 1 = gcd ( a , b ) b x 2 + ( a m o d b ) y 2 = gcd ( b , a m o d b ) ∵ gcd ( a , b ) = gcd ( b , a m o d b ) ∴ a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 ∴ x 1 = y 2 , y 1 = x 2 − ⌊ a b ⌋ y 2 ax+by=\gcd(a,b)\\ 设 \begin{cases} ax_1+by_1=\gcd(a,b)\\ bx_2+(a \mod b)y_2=\gcd(b,a\mod b)\\ \end{cases}\\ \because \gcd(a,b)=\gcd(b,a\mod b)\\ \therefore ax_1+by_1=bx_2+(a\mod b)y_2\\ \therefore x_1=y_2,y_1=x_2-\left\lfloor\dfrac{a}{b}\right\rfloor y_2 a x + b y = g cd( a , b ) 设 { a x 1 + b y 1 = g cd( a , b ) b x 2 + ( a m o d b ) y 2 = g cd( b , a m o d b ) ∵ g cd( a , b ) = g cd( b , a m o d b ) ∴ a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 ∴ x 1 = y 2 , y 1 = x 2 − ⌊ b a ⌋ y 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int Exgcd (int a, int b, int &x, int &y) { if (!b) { x = 1 ; y = 0 ; return a; } int d = Exgcd (b, a % b, x, y); int t = x; x = y; y = t - (a / b) * y; return d; }
CRT中国剩余定理 (Chinese Remainder Theorem, CRT)
解如下方程组
{ x ≡ a 1 ( m o d n 1 ) x ≡ a 2 ( m o d n 2 ) ⋯ x ≡ a k ( m o d n k ) \begin{cases} x \equiv a_1 \pmod {n_1}\\ x \equiv a_2 \pmod {n_2}\\ \cdots \\ x \equiv a_k \pmod {n_k}\\ \end{cases} ⎩ ⎪ ⎪ ⎪ ⎨ ⎪ ⎪ ⎪ ⎧ x ≡ a 1 ( m o d n 1 ) x ≡ a 2 ( m o d n 2 ) ⋯ x ≡ a k ( m o d n k )
令 N = ∏ i = 1 k n i N=\prod \limits^{k}_{i=1} n_i N = i = 1 ∏ k n i
对于第 i i i 个方程
令
m i = N n i c i = m i ⋅ m i − 1 m_i=\frac{N}{n_i}\\ c_i=m_i\cdot m_i^{-1} m i = n i N c i = m i ⋅ m i − 1
其中, m i m_i m i 关于 n i n_i n i 的逆元可以用 e x g c d exgcd e x g c d 求得
方程组的解 x ≡ ∑ i = 1 k a i c i ( m o d N ) x\equiv \sum\limits^{k}_{i=1}a_ic_i \pmod N x ≡ i = 1 ∑ k a i c i ( m o d N )
1 2 3 4 5 6 7 8 9 10 11 12 13 LL CRT (int k, LL* a, LL* r) { LL n = 1 , ans = 0 ; for (int i = 1 ; i <= k; i++) n = n * r[i]; for (int i = 1 ; i <= k; i++) { LL m = n / r[i], b, y; exgcd (m, r[i], b, y); ans = (ans + a[i] * m * b % n) % n; } return (ans % n + n) % n; }