This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub fffelix-huang/CP-stuff
#include "library/math/crt.hpp"
找 $x$ 使得 $x \equiv r[i] \pmod{m[i]}$。如果無解的話回傳 $(0, 0)$。
時間複雜度:$O(n \log{\mathrm{lcm}(m[i])})$
AtCoder Library document
#pragma once #include <vector> #include <tuple> #include <cassert> #include <algorithm> #include "safe-mod.hpp" #include "inv-gcd.hpp" namespace felix { // (rem, mod) template<class T> std::pair<T, T> crt(const std::vector<T>& r, const std::vector<T>& m) { assert(r.size() == m.size()); int n = (int) r.size(); // Contracts: 0 <= r0 < m0 T r0 = 0, m0 = 1; for(int i = 0; i < n; i++) { assert(1 <= m[i]); T r1 = internal::safe_mod(r[i], m[i]); T m1 = m[i]; if(m0 < m1) { std::swap(r0, r1); std::swap(m0, m1); } if(m0 % m1 == 0) { if(r0 % m1 != r1) { return {0, 0}; } continue; } T g, im; std::tie(g, im) = internal::inv_gcd(m0, m1); T u1 = (m1 / g); if((r1 - r0) % g) { return {0, 0}; } T x = (r1 - r0) / g % u1 * im % u1; r0 += x * m0; m0 *= u1; if(r0 < 0) { r0 += m0; } } return {r0, m0}; } } // namespace felix
#line 2 "library/math/crt.hpp" #include <vector> #include <tuple> #include <cassert> #include <algorithm> #line 2 "library/math/safe-mod.hpp" namespace felix { namespace internal { template<class T> constexpr T safe_mod(T x, T m) { x %= m; if(x < 0) { x += m; } return x; } } // namespace internal } // namespace felix #line 3 "library/math/inv-gcd.hpp" namespace felix { namespace internal { template<class T> constexpr std::pair<T, T> inv_gcd(T a, T b) { a = safe_mod(a, b); if(a == 0) { return {b, 0}; } T s = b, t = a; T m0 = 0, m1 = 1; while(t) { T u = s / t; s -= t * u; m0 -= m1 * u; auto tmp = s; s = t; t = tmp; tmp = m0; m0 = m1; m1 = tmp; } if(m0 < 0) { m0 += b / s; } return {s, m0}; } } // namespace internal } // namespace felix #line 8 "library/math/crt.hpp" namespace felix { // (rem, mod) template<class T> std::pair<T, T> crt(const std::vector<T>& r, const std::vector<T>& m) { assert(r.size() == m.size()); int n = (int) r.size(); // Contracts: 0 <= r0 < m0 T r0 = 0, m0 = 1; for(int i = 0; i < n; i++) { assert(1 <= m[i]); T r1 = internal::safe_mod(r[i], m[i]); T m1 = m[i]; if(m0 < m1) { std::swap(r0, r1); std::swap(m0, m1); } if(m0 % m1 == 0) { if(r0 % m1 != r1) { return {0, 0}; } continue; } T g, im; std::tie(g, im) = internal::inv_gcd(m0, m1); T u1 = (m1 / g); if((r1 - r0) % g) { return {0, 0}; } T x = (r1 - r0) / g % u1 * im % u1; r0 += x * m0; m0 *= u1; if(r0 < 0) { r0 += m0; } } return {r0, m0}; } } // namespace felix