#line 1 "remote_test\\yuki\\math\\187.0.test.cpp" #define PROBLEM "https://yukicoder.me/problems/448" #line 1 "math\\cra.hpp" #line 1 "common.hpp" #define LIB_DEBUG #define LIB_BEGIN namespace lib { #define LIB_END } #define LIB ::lib:: #line 1 "math\\extended_gcd.hpp" #line 5 "math\\extended_gcd.hpp" #include #include #include LIB_BEGIN // Input: integer `a` and `b`. // Output: (x, y, z) such that `a`x + `b`y = z = gcd(`a`, `b`). [[deprecated]] std::tuple ext_gcd(long long a, long long b) { long long x11 = 1, x12 = 0, x21 = 0, x22 = 1; while (b != 0) { long long q = a / b, x11_cpy = x11, x12_cpy = x12, a_cpy = a; x11 = x21, x21 = x11_cpy - q * x21; x12 = x22, x22 = x12_cpy - q * x22; a = b, b = a_cpy - q * b; } return std::make_tuple(x11, x12, a); } // Input: integer `a` and `b`. // Output: (x, gcd(`a`, `b`)) such that `a`x ≡ gcd(`a`, `b`) (mod `b`). std::pair inv_gcd(long long a, long long b) { long long x11 = 1, x21 = 0; while (b != 0) { long long q = a / b, x11_cpy = x11, a_cpy = a; x11 = x21, x21 = x11_cpy - q * x21; a = b, b = a_cpy - q * b; } return std::make_pair(x11, a); } namespace detail { template class modular_inverse { std::vector ivs{ModIntT()}; enum : int { LIM = 1 << 20 }; public: modular_inverse() {} ModIntT operator()(int k) { // assume `ModIntT::mod()` is prime. if (k > LIM) return ModIntT(k).inv(); // preprocess modular inverse from 1 to `k` if (int n = static_cast(ivs.size()); n <= k) { int nn = n; while (nn <= k) nn <<= 1; ivs.resize(nn); ModIntT v(1); for (int i = n; i != nn; ++i) ivs[i] = v, v *= ModIntT(i); v = v.inv(); for (int i = nn - 1; i >= n; --i) ivs[i] *= v, v *= ModIntT(i); } return ivs[k]; } }; } // namespace detail LIB_END #line 6 "math\\cra.hpp" #include #include #include #line 12 "math\\cra.hpp" LIB_BEGIN namespace detail { std::optional> cra2(long long a0, long long m0, long long a1, long long m1) { if (m0 < m1) return cra2(a1, m1, a0, m0); auto [x, d] = inv_gcd(m0, m1); auto a1_a0 = a1 - a0; // assume `a0` < `m0` and `a1` < `m1` auto a1_a0_d = a1_a0 / d; if (a1_a0 != a1_a0_d * d) return {}; auto m1_d = m1 / d; auto k0 = x % m1_d * (a1_a0_d % m1_d) % m1_d; if (k0 < 0) k0 += m1_d; return std::make_pair(a0 + k0 * m0, m0 * m1_d); } } // namespace detail // Returns (remainder, modular) std::optional> cra(const std::vector &a, const std::vector &m) { const int n = static_cast(a.size()); assert(a.size() == m.size()); auto safe_mod = [](long long a, long long m) { return a %= m, (a < 0 ? a + m : a); }; long long A = 0, M = 1; for (int i = 0; i < n; ++i) { auto res = detail::cra2(safe_mod(a[i], m[i]), m[i], A, M); if (!res) return {}; std::tie(A, M) = res.value(); } return std::make_pair(A, M); } std::optional> cra_mod(const std::vector &a, const std::vector &m, const int modular) { const int n = static_cast(a.size()); assert(a.size() == m.size()); auto safe_mod = [](int a, int m) { if ((a %= m) < 0) a += m; return a; }; std::vector m_cpy(m); // check conflicts and make coprime for (int i = 0; i != n; ++i) { auto &&mi = m_cpy[i]; for (int j = 0; j != i; ++j) { auto &&mj = m_cpy[j]; auto d = std::gcd(mi, mj); if (d == 1) continue; if (safe_mod(a[i], d) != safe_mod(a[j], d)) return {}; mi /= d, mj /= d; auto k = std::gcd(mi, d); if (k != 1) while (d % k == 0) mi *= k, d /= k; mj *= d; } } m_cpy.push_back(modular); std::vector pp(n + 1, 1), res(n + 1); for (int i = 0; i != n; ++i) { auto u = (safe_mod(a[i], m_cpy[i]) - res[i]) * inv_gcd(pp[i], m_cpy[i]).first % m_cpy[i]; if (u < 0) u += m_cpy[i]; for (int j = i + 1; j <= n; ++j) { res[j] = (res[j] + u * pp[j]) % m_cpy[j]; pp[j] = static_cast(pp[j]) * m_cpy[i] % m_cpy[j]; } } return std::make_pair(res.back(), pp.back()); } LIB_END #line 4 "remote_test\\yuki\\math\\187.0.test.cpp" #include #include #line 8 "remote_test\\yuki\\math\\187.0.test.cpp" int main() { #ifdef LOCAL std::freopen("in", "r", stdin), std::freopen("out", "w", stdout); #endif std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n; std::cin >> n; std::vector a(n), m(n); for (int i = 0; i != n; ++i) std::cin >> a[i] >> m[i]; auto res = lib::cra_mod(a, m, 1000000007); if (res) { if (std::all_of(a.begin(), a.end(), [](int n) { return n == 0; })) { std::cout << res->second << '\n'; } else { std::cout << res->first << '\n'; } } else { std::cout << -1 << '\n'; } return 0; }