Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Chinese Remainder Theorem

poyo
November 24, 2018
140

Chinese Remainder Theorem

poyo

November 24, 2018
Tweet

Transcript

  1. 中国剰余定理(CRT) m , m :互いに素な正整数、a , a ∈ Z に対して連立方程式

    を満たす x (0 ≤ x < m m ) が存在する のでそれを求める 1 2 1 2 x ≡ a mod. m 1 1 x ≡ a mod. m 2 2 1 2
  2. x := a とすれば1つ目の式は満たされる このとき x + (a − x)m

    t も1つ目の式を満たすが、もし m t = 1 − m t とできれば2つ目の式も満たす m ∤ (a − x) なら x が打ち消し合って m での剰余は a の みが残るのでok m ∣ (a − x) なら x が残るが x ≡ a mod. m なのでok m , m は互いに素だから m t + m t = 1 となる t , t は拡張 ユークリッドの互除法で求められる 1 2 1 1 1 1 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 1 2
  3. 実装例 (ruby) def crt(a1, a2, m1, m2) x, y, g

    = ext_gcd(m1, m2) # g == 1 じゃないとダメ (a1 + (a2 - a1) * m1 * g) % (m1 * m2) end 実装例 (C++) using i64 = int64_t; i64 crt(i64 a1, i64 a2, i64 m1, i64 m2) { auto xyg = ext_gcd(m1, m2); // xyg[2] == 1 じゃないとダメ auto ret = a1 + (a2 - a1) % m2 * m1 * xyg[0] % m2, m = m1 * m2; return (ret % m + m) % m; }
  4. 実装の注意 (C++) % m2 しておかないと、3つの数の積なのですぐオーバーフローする t , t が m

    t + m t = 1 を満たすなら t ← t + km としても解になる(t のほうを調整すればいい) なので互除法で得られる解がめちゃでかくなりうる t ← t %m しとけば m 未満になる ついでに a − a も m で mod をとっておく 上の考察で割り切れるかどうかはどうでもいいことが分か ったので mod をとっていい ret % m は ret が負のときいやな感じになる -17 % 5 = -2 になる ruby などは -17 % 5 = 3 になる 1 2 1 1 2 2 1 1 2 2 1 1 2 2 2 1 2
  5. 法が互いに素とは限らない場合 を満たす x が存在する必要十分条件は a ≡ a mod. gcd(m ,

    m ) である。また、x は 0 ≤ x < lcm(m , m ) の範囲で一意 x ≡ a mod. m 1 1 x ≡ a mod. m 2 2 1 2 1 2 1 2
  6. 互いに素のときと同じ a + (a − a )m t が解になってほしい いま、m

    t = g − m t where g := gcd(m , m ) とできる さらに g ∣ (a − a ) が成り立っているから、結局、微妙に変更して a + m t とすれば解になる mod. m が a になるのは良い 式変形すると a + (a − a ) − m t となるの で、互いに素のときと同じ考察で mod. m で a と分かる 1 2 1 1 1 1 1 2 2 1 2 2 1 1 g a − a 2 1 1 1 1 1 1 { 2 1 g a − a 2 1 2 2 } 2 2
  7. 実装例 (ruby) def crt(a1, a2, m1, m2) x, y, g

    = ext_gcd(m1, m2) return [-1, 0] if (a1 - a2) % g > 0 # 解なし lcm = m1 * m2 / g [(a1 + (a2 - a1) / g * m1 * x) % lcm, lcm] end
  8. n 個の連立方程式の場合 それぞれの方程式が x ≡ a mod. m の形で表されるとすると、解が存在する条件は ∀i,

    j に対して a ≡ a mod. gcd(m , m ) が成り立つこと 実装する際は、前から2つ方程式を取ってきて解いた結果を新しく制約と していけばいい i i i j i j
  9. 例. a = [2, 3, 3] m = [3, 5,

    10] ans, mod = 0, 1 # 任意の整数は mod. 1 で 0 a.zip(m).each do |aa, mm| ans, mod = crt(ans, aa, mod, mm) end puts ans # => 23 x x x ≡ 2 mod. 3 ≡ 3 mod. 5 ≡ 3 mod. 10