Yukicoder No.187 中華風 (Hard)

,

CRTはCTFのcrypto問で使うからライブラリにあるんですよと言いながらNo.186 中華風 (Easy)を解いたら、そのままこちらも解けていた。

solution

中国人剰余定理ほぼそのまま。 ただし法$M_i$が互いに素とは限らないのでいい感じにし、$10^9+7$での剰余は最後にのみ取る。 整数演算を定数時間と見て$O(N)$だが、桁数は$O(N\log_{10}(\max Y_i))$ (この問題の制約では最大で$10$進$9000$桁)となる。

implementation

#!/usr/bin/env python3
import functools
import math
lcm = lambda a, b: a * b // math.gcd(a, b)
def extgcd(a, b):
    if b == 0:
        return 1, 0
    else:
        na, nb = extgcd(b, a % b)
        return nb, na - a//b * nb
def modinv(a, n):
    return extgcd(a, n)[0] % n
def crt(eqn1, eqn2):
    x1, m1 = eqn1
    x2, m2 = eqn2
    d = math.gcd(m1, m2)
    x = x1 + (m1 // d) * (x2 - x1) * modinv(m1 // d, m2 // d)
    m = lcm(m1, m2)
    return x % m, m
n = int(input())
eqn = [ tuple(map(int, input().split())) for _ in range(n) ]
ans, _ = functools.reduce(crt, eqn)
if ans == 0:
    ans += functools.reduce(lcm, map(lambda it: it[1], eqn))
for x, y in eqn:
    if ans % y != x:
        ans = -1
        break
else:
    ans %= 10**9+7
print(ans)