This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "tools/extended_garner.hpp"
template <typename Iterator, typename ModType>
std::optional<std::pair<long long, long long>> extended_garner(Iterator begin, Iterator end, ModType M);
template <typename M, typename Iterator>
std::optional<std::pair<M, M>> extended_garner(Iterator begin, Iterator end);
Given an array of the pairs $(r_i, m_i)$ with length $n$, it solves the modular equation system
\[\begin{align*} x \equiv r_i \pmod{m_i}, \forall i \in \{0, 1, \ldots, n - 1\} \end{align*}\]If there is no solution, it returns std::nullopt
.
Otherwise, all the solutions can be written as the form $x \equiv y \pmod{z}$, using integers $y, z \, (0 \leq y < z = \mathrm{lcm}(m_i))$.
It returns this $(y \pmod{m}, z \pmod{m})$ as a pair.
If $n = 0$, it returns $(0, 1)$.
#ifndef TOOLS_EXTENDED_GARNER_HPP
#define TOOLS_EXTENDED_GARNER_HPP
#include <optional>
#include <utility>
#include <cstdint>
#include <vector>
#include <cstddef>
#include "tools/mod.hpp"
#include "tools/garner.hpp"
// Source: https://qiita.com/drken/items/ae02240cd1f8edfc86fd
// License: unknown
// Author: drken
namespace tools {
template <typename Iterator, typename ModType>
::std::optional<::std::pair<long long, long long>> extended_garner(const Iterator& begin, const Iterator& end, const ModType& mod) {
::std::vector<::std::pair<long long, long long>> v;
for (auto it = begin; it != end; ++it) {
v.emplace_back(::tools::mod(it->first, it->second), it->second);
}
for (::std::size_t i = 0; i < v.size(); ++i) {
for (::std::size_t j = 0; j < i; ++j) {
long long g = ::std::gcd(v[i].second, v[j].second);
if ((v[i].first - v[j].first) % g != 0) return ::std::nullopt;
v[i].second /= g;
v[j].second /= g;
long long gi = ::std::gcd(v[i].second, g);
long long gj = g / gi;
do {
g = ::std::gcd(gi, gj);
gi *= g;
gj /= g;
} while (g != 1);
v[i].second *= gi;
v[j].second *= gj;
v[i].first %= v[i].second;
v[j].first %= v[j].second;
}
}
return ::std::optional<::std::pair<long long, long long>>(::tools::garner(v.begin(), v.end(), mod));
}
template <typename M, typename Iterator>
::std::optional<::std::pair<M, M>> extended_garner(const Iterator& begin, const Iterator& end) {
const auto result = ::tools::extended_garner(begin, end, M::mod());
if (!result) return ::std::nullopt;
return ::std::make_optional<::std::pair<M, M>>(M::raw(result->first), M::raw(result->second));
}
}
#endif
#line 1 "tools/extended_garner.hpp"
#include <optional>
#include <utility>
#include <cstdint>
#include <vector>
#include <cstddef>
#line 1 "tools/mod.hpp"
#include <cassert>
#include <type_traits>
#line 1 "tools/is_integral.hpp"
#line 5 "tools/is_integral.hpp"
namespace tools {
template <typename T>
struct is_integral : ::std::is_integral<T> {};
template <typename T>
inline constexpr bool is_integral_v = ::tools::is_integral<T>::value;
}
#line 7 "tools/mod.hpp"
namespace tools {
template <typename M, typename N> requires (
::tools::is_integral_v<M> && !::std::is_same_v<::std::remove_cv_t<M>, bool> &&
::tools::is_integral_v<N> && !::std::is_same_v<::std::remove_cv_t<N>, bool>)
constexpr ::std::common_type_t<M, N> mod(const M a, const N b) noexcept {
assert(b != 0);
using UM = ::std::make_unsigned_t<M>;
using UN = ::std::make_unsigned_t<N>;
const UM ua = a >= 0 ? a : static_cast<UM>(-(a + 1)) + 1;
const UN ub = b >= 0 ? b : static_cast<UN>(-(b + 1)) + 1;
auto r = ua % ub;
if (a < 0 && r > 0) {
r = ub - r;
}
return r;
}
}
#line 1 "tools/garner.hpp"
#line 1 "tools/inv_mod.hpp"
#line 1 "tools/extgcd.hpp"
#include <tuple>
#line 7 "tools/extgcd.hpp"
#include <algorithm>
#line 1 "tools/abs.hpp"
namespace tools {
constexpr float abs(const float x) {
return x < 0 ? -x : x;
}
constexpr double abs(const double x) {
return x < 0 ? -x : x;
}
constexpr long double abs(const long double x) {
return x < 0 ? -x : x;
}
constexpr int abs(const int x) {
return x < 0 ? -x : x;
}
constexpr long abs(const long x) {
return x < 0 ? -x : x;
}
constexpr long long abs(const long long x) {
return x < 0 ? -x : x;
}
constexpr unsigned int abs(const unsigned int x) {
return x;
}
constexpr unsigned long abs(const unsigned long x) {
return x;
}
constexpr unsigned long long abs(const unsigned long long x) {
return x;
}
}
#line 9 "tools/extgcd.hpp"
namespace tools {
template <typename T>
::std::tuple<T, T, T> extgcd(T prev_r, T r) {
const bool prev_r_is_neg = prev_r < T(0);
const bool r_is_neg = r < T(0);
if (prev_r_is_neg) prev_r = -prev_r;
if (r_is_neg) r = -r;
#ifndef NDEBUG
const T a = prev_r;
const T b = r;
#endif
T prev_s(1);
T prev_t(0);
T s(0);
T t(1);
while (r != T(0)) {
const T q = prev_r / r;
::std::tie(prev_r, r) = ::std::make_pair(r, prev_r - q * r);
::std::tie(prev_s, s) = ::std::make_pair(s, prev_s - q * s);
::std::tie(prev_t, t) = ::std::make_pair(t, prev_t - q * t);
}
if (prev_r_is_neg) prev_s = -prev_s;
if (r_is_neg) prev_t = -prev_t;
assert(::tools::abs(prev_s) <= ::std::max(b / prev_r / T(2), T(1)));
assert(::tools::abs(prev_t) <= ::std::max(a / prev_r / T(2), T(1)));
return ::std::make_tuple(prev_s, prev_t, prev_r);
}
}
#line 7 "tools/inv_mod.hpp"
namespace tools {
template <typename T1, typename T2>
constexpr T2 inv_mod(const T1 x, const T2 m) {
const auto [x0, y0, gcd] = ::tools::extgcd(x, m);
assert(gcd == 1);
return ::tools::mod(x0, m);
}
}
#line 9 "tools/garner.hpp"
// Source: https://qiita.com/drken/items/ae02240cd1f8edfc86fd
// License: unknown
// Author: drken
namespace tools {
template <typename Iterator, typename ModType>
::std::pair<long long, long long> garner(const Iterator& begin, const Iterator& end, const ModType& mod) {
::std::vector<long long> b, m;
for (auto it = begin; it != end; ++it) {
b.push_back(::tools::mod(it->first, it->second));
m.push_back(it->second);
}
auto lcm = 1LL;
for (::std::size_t i = 0; i < b.size(); ++i) {
(lcm *= m[i]) %= mod;
}
m.push_back(mod);
::std::vector<long long> coeffs(m.size(), 1);
::std::vector<long long> constants(m.size(), 0);
for (::std::size_t k = 0; k < b.size(); ++k) {
long long t = ::tools::mod((b[k] - constants[k]) * ::tools::inv_mod(coeffs[k], m[k]), m[k]);
for (::std::size_t i = k + 1; i < m.size(); ++i) {
(constants[i] += t * coeffs[i]) %= m[i];
(coeffs[i] *= m[k]) %= m[i];
}
}
return ::std::make_pair(constants.back(), lcm);
}
template <typename M, typename Iterator>
::std::pair<M, M> garner(const Iterator& begin, const Iterator& end) {
const auto [y, z] = ::tools::garner(begin, end, M::mod());
return ::std::make_pair(M::raw(y), M::raw(z));
}
}
#line 11 "tools/extended_garner.hpp"
// Source: https://qiita.com/drken/items/ae02240cd1f8edfc86fd
// License: unknown
// Author: drken
namespace tools {
template <typename Iterator, typename ModType>
::std::optional<::std::pair<long long, long long>> extended_garner(const Iterator& begin, const Iterator& end, const ModType& mod) {
::std::vector<::std::pair<long long, long long>> v;
for (auto it = begin; it != end; ++it) {
v.emplace_back(::tools::mod(it->first, it->second), it->second);
}
for (::std::size_t i = 0; i < v.size(); ++i) {
for (::std::size_t j = 0; j < i; ++j) {
long long g = ::std::gcd(v[i].second, v[j].second);
if ((v[i].first - v[j].first) % g != 0) return ::std::nullopt;
v[i].second /= g;
v[j].second /= g;
long long gi = ::std::gcd(v[i].second, g);
long long gj = g / gi;
do {
g = ::std::gcd(gi, gj);
gi *= g;
gj /= g;
} while (g != 1);
v[i].second *= gi;
v[j].second *= gj;
v[i].first %= v[i].second;
v[j].first %= v[j].second;
}
}
return ::std::optional<::std::pair<long long, long long>>(::tools::garner(v.begin(), v.end(), mod));
}
template <typename M, typename Iterator>
::std::optional<::std::pair<M, M>> extended_garner(const Iterator& begin, const Iterator& end) {
const auto result = ::tools::extended_garner(begin, end, M::mod());
if (!result) return ::std::nullopt;
return ::std::make_optional<::std::pair<M, M>>(M::raw(result->first), M::raw(result->second));
}
}