#define INF 4'000'000'000'000'000'037LL // https://github.com/miscalculation53/library/tree/wip/template/template_all.hpp // https://github.com/miscalculation53/library/tree/wip/template/template_all_but_modint.hpp // https://github.com/miscalculation53/library/tree/wip/template/template_types.hpp #include using namespace std; using ll = long long; using uint = unsigned int; using ull = unsigned long long; using pll = pair; using tllll = tuple; #define vc vector template using vvc = vc>; using vl = vc; using vstr = vc; template using pql = priority_queue, greater>; using i128 = __int128_t; using u128 = __uint128_t; i128 stoi128(const string &s) { const bool neg = s.front() == '-'; u128 res = 0; for (int i = neg; i < (int)s.size(); i++) res = 10 * res + s[i] - '0'; if (neg) return -i128(res - 1) - 1; return i128(res); } string i128tos(i128 x) { if (x == 0) return "0"; string sign = "", res = ""; u128 ux; if (x < 0) ux = u128(-(x + 1)) + 1, sign = "-"; else ux = x; while (ux > 0) { res += '0' + ux % 10; ux /= 10; } reverse(res.begin(), res.end()); return sign + res; } istream &operator>>(istream &is, i128 &a) { string s; is >> s; a = stoi128(s); return is; } ostream &operator<<(ostream &os, const i128 &a) { os << i128tos(a); return os; } #define cauto const auto // https://github.com/miscalculation53/library/tree/wip/template/template_rep.hpp #define overload4(_1,_2,_3,_4,name,...) name #define rep2(i,l,r) for (ll i = ll(l), rrrrr = ll(r); i < rrrrr; i++) #define rep(...) overload4(__VA_ARGS__, rep3, rep2, rep1)(__VA_ARGS__) #define repi1(i,n) for (int i = 0, nnnnn = int(n); i < nnnnn; i++) #define repi2(i,l,r) for (int i = int(l), rrrrr = int(r); i < rrrrr; i++) #define repi3(i,l,r,d) for (int i = int(l), rrrrr = int(r), ddddd = int(d); ddddd > 0 ? i < rrrrr : i > rrrrr; i += d) #define repi(...) overload4(__VA_ARGS__, repi3, repi2, repi1)(__VA_ARGS__) #define fe(...) for (auto __VA_ARGS__) #define fec(...) for (cauto &__VA_ARGS__) #define fem(...) for (auto &__VA_ARGS__) // https://github.com/miscalculation53/library/tree/wip/template/template_math.hpp // https://github.com/miscalculation53/library/tree/wip/utils/is_integral_ext.hpp template constexpr bool is_integral_ext = is_integral_v || is_same_v || is_same_v; template constexpr bool is_signed_ext = is_signed_v || is_same_v; template constexpr bool is_unsigned_ext = is_unsigned_v || is_same_v; template inline bool chmin(T &a, U b) { return a > b ? a = b, true : false; } template inline bool chmax(T &a, U b) { return a < b ? a = b, true : false; } template && is_integral_ext>> inline constexpr T divfloor(U a, V b) { return T(a) / T(b) - (T(a) % T(b) && (T(a) ^ T(b)) < 0); } template && is_integral_ext>> inline constexpr T safemod(U a, V b) { return T(a) - T(b) * divfloor(a, b); } template constexpr T ipow(U a, V b) { assert(b >= 0); if (b == 0) return 1; if (a == 0 || a == 1) return a; if (a < 0 && a == -1) return b & 1 ? -1 : 1; T res = 1, tmp = a; while (true) { if (b & 1) res *= tmp; b >>= 1; if (b == 0) break; tmp *= tmp; } return res; } // https://github.com/miscalculation53/library/tree/wip/template/template_vector.hpp #define ALL(a) (a).begin(), (a).end() template inline T SZ(const V &x) { return x.size(); } #define eb emplace_back #define LMD(x,fx) ([&](auto x) { return fx; }) // https://github.com/miscalculation53/library/tree/wip/template/template_algo.hpp // https://github.com/miscalculation53/library/tree/wip/utils/resolved_value.hpp template , long> = 0> const T &resolved_value() { static const T value = T(x()); return value; } template vvc top(const vvc &a) { if (a.empty()) return {}; const int n = a.size(), m = a[0].size(); vvc b(m, vc(n)); repi(i, n) { assert(SZ(a[i]) == m); repi(j, m) b[j][i] = a[i][j]; } return b; } vstr top(const vstr &a) { vvc a_(a.size()); repi(i, SZ(a)) a_[i] = {ALL(a[i])}; vvc b_ = top(a_); vstr b(b_.size()); repi(i, SZ(b)) b[i] = {ALL(b_[i])}; return b; } template struct has_e0 : false_type {}; template struct has_e0> : true_type {}; template inline constexpr bool has_e0_v = has_e0::value; template struct MonoidAdd { using S = T; static constexpr S op(S a, S b) { return a + b; } static constexpr S e() { if constexpr (has_e0_v) return S::e0(); else return {}; } }; namespace internal { template struct HasMonoidPow : false_type { }; template struct HasMonoidPow(), declval()))>> : true_type { }; } template vc cuml(const vc &v, int left_index = 0) { const int n = v.size(); vc res(n + 1); res[0] = M::e(); repi(i, n) res[i + 1] = M::op(res[i], v[i]); res.erase(res.begin(), res.begin() + left_index); return res; } template vc cumlsum(const vc &v, int left_index = 0) { return cuml>(v, left_index); } constexpr array DRULgrid = {{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}}; constexpr array DRULplane = {{{0, -1}, {1, 0}, {0, 1}, {-1, 0}}}; // https://github.com/miscalculation53/library/tree/wip/template/template_binsearch.hpp template struct is_random_access_iterator { static constexpr bool value = is_same_v< typename iterator_traits::iterator_category, random_access_iterator_tag >; }; template constexpr bool is_random_access_iterator_v = is_random_access_iterator::value; namespace internal { template bool binsearch_adjacent(T a, T b) { if (a < b) return a + 1 == b; if (b < a) return b + 1 == a; return false; } }; template pair binsearch(const Judge &judge, InitOk init_ok, InitNg init_ng, bool check_ok = true, bool check_ng = true) { T ok(init_ok), ng(init_ng); if (check_ok) assert(judge(ok)); if (check_ng) assert(!judge(ng)); while (!internal::binsearch_adjacent(ok, ng)) { T mid = (ok & ng) + ((ok ^ ng) >> 1); (judge(mid) ? ok : ng) = mid; } return {ok, ng}; } // https://github.com/miscalculation53/library/tree/wip/template/template_bit.hpp template inline constexpr ull MASK(T k) { return (1ULL << k) - 1ULL; } inline constexpr ll bit_width(ll x) { return std::bit_width((ull)x); } inline constexpr ll bit_ceil(ll x) { return std::bit_ceil((ull)x); } inline constexpr ll countr_zero(ll x) { assert(x != 0); return std::countr_zero((ull)x); } // https://github.com/miscalculation53/library/tree/wip/template/template_inout.hpp // https://github.com/miscalculation53/library/tree/wip/template/template_dump.hpp #define dump(...) #define oj(...) __VA_ARGS__ namespace fastio { template struct unsigned_integer { using type = make_unsigned_t; }; template <> struct unsigned_integer { using type = u128; }; template <> struct unsigned_integer { using type = u128; }; template using unsigned_integer_t = typename unsigned_integer::type; static constexpr uint32_t SIZ = 1 << 17; char ibuf[SIZ]; char obuf[SIZ]; char out[100]; uint32_t pil = 0, pir = 0, por = 0; struct Pre { char num[10000][4]; constexpr Pre() : num() { for (int i = 0; i < 10000; i++) { int n = i; for (int j = 3; j >= 0; j--) { num[i][j] = n % 10 | '0'; n /= 10; } } } } constexpr pre; inline void load() { memcpy(ibuf, ibuf + pil, pir - pil); pir = pir - pil + fread(ibuf + pir - pil, 1, SIZ - pir + pil, stdin); pil = 0; if (pir < SIZ) ibuf[pir++] = '\n'; } inline void flush() { fwrite(obuf, 1, por, stdout); por = 0; } void rd1(char &c) { do { if (pil + 1 > pir) load(); c = ibuf[pil++]; } while (c <= ' '); } void rd1(string &x) { x.clear(); while (true) { if (pil == pir) load(); while (pil < pir && ibuf[pil] <= ' ') ++pil; if (pil < pir) break; } while (true) { uint32_t p = pil; while (pil < pir && ibuf[pil] > ' ') ++pil; x.append(ibuf + p, pil - p); if (pil < pir) { ++pil; return; } load(); } } template void rd1_real(T &x) { string s; rd1(s); if constexpr (!is_same_v) { auto [p, ec] = from_chars(s.data(), s.data() + s.size(), x); if (ec == errc{} && p == s.data() + s.size()) return; } if constexpr (is_same_v) x = stold(s); else x = stod(s); } template void rd1_integer(T &x) { using U = unsigned_integer_t; bool minus = false; U val = 0; if constexpr (check_buffer) if (pil + 100 > pir) load(); uint32_t p = pil; while (ibuf[p] < '-') ++p; if constexpr (is_signed::value || is_same_v) { if (ibuf[p] == '-') minus = true, ++p; } while ('0' <= ibuf[p]) val = val * 10 + (ibuf[p++] & 15); pil = p; if constexpr (is_signed::value || is_same_v) { if (minus) { const U min_abs = U(numeric_limits::max()) + 1; x = val == min_abs ? numeric_limits::lowest() : -T(val); } else x = T(val); } else x = T(val); } void rd1(int &x) { rd1_integer(x); } void rd1(ll &x) { rd1_integer(x); } void rd1(i128 &x) { rd1_integer(x); } void rd1(uint &x) { rd1_integer(x); } void rd1(ull &x) { rd1_integer(x); } void rd1(u128 &x) { rd1_integer(x); } void rd1(double &x) { rd1_real(x); } void rd1(long double &x) { rd1_real(x); } template void rd1(tuple &tpl) { apply([](auto &...x) { (rd1(x), ...); }, tpl); } template void rd1(vc &x) { for (auto &d: x) rd1(d); } template void read(T &...x) { if constexpr (sizeof...(T) <= SIZ / 100 && ((!is_same_v && (is_integral_v || is_same_v || is_same_v)) && ...)) { if (pil + 100 * sizeof...(T) > pir) load(); (rd1_integer(x), ...); } else (rd1(x), ...); } void wt1(const char c) { if (por == SIZ) flush(); obuf[por++] = c; } void wt1(string_view s) { while (!s.empty()) { if (por == SIZ) flush(); size_t n = min(s.size(), SIZ - por); memcpy(obuf + por, s.data(), n); por += n; s.remove_prefix(n); } } template void wt1_integer(T x) { if (por > SIZ - 100) flush(); using U = unsigned_integer_t; U ux; if constexpr (is_signed::value || is_same_v) { if (x < 0) obuf[por++] = '-', ux = U(0) - U(x); else ux = U(x); } else ux = x; int outi; for (outi = 96; ux >= 10000; outi -= 4) { memcpy(out + outi, pre.num[ux % 10000], 4); ux /= 10000; } if (ux >= 1000) { memcpy(obuf + por, pre.num[ux], 4); por += 4; } else if (ux >= 100) { memcpy(obuf + por, pre.num[ux] + 1, 3); por += 3; } else if (ux >= 10) { int q = (ux * 103) >> 10; obuf[por] = q | '0'; obuf[por + 1] = (ux - q * 10) | '0'; por += 2; } else obuf[por++] = ux | '0'; memcpy(obuf + por, out + outi + 4, 96 - outi); por += 96 - outi; } template void wt1_real(T x) { if constexpr (!is_same_v) { auto [p, ec] = to_chars(out, out + sizeof(out), x, chars_format::fixed, 15); if (ec == errc{}) { wt1(string_view(out, p)); return; } } ostringstream oss; oss << fixed << setprecision(15) << x; wt1(oss.str()); } void wt1(int x) { wt1_integer(x); } template , int> = 0> void wt1(T x); void wt1(i128 x) { wt1_integer(x); } void wt1(u128 x) { wt1_integer(x); } void wt1(double x) { wt1_real(x); } void wt1(long double x) { wt1_real(x); } template void wt1(const pair &val); template void wt1(const tuple &tpl); template void wt1(const array &val); template void wt1(const vector &val); template void write(T &&...x) { (wt1(std::forward(x)), ...); } template void print(T &&...x) { if constexpr (sizeof...(T)) { int i = 0; ((i++ ? wt1(' ') : void(), wt1(std::forward(x))), ...); } wt1('\n'); } } struct Dummy { Dummy() { atexit(fastio::flush); } } dummy; namespace internal { template void READnodump(Ts &...a) { fastio::read(a...); } template void READVECnodump(int n, vc &...v) { (v.resize(n), ...); READnodump(v...); } }; #define READ(...) internal::READnodump(__VA_ARGS__); dump(__VA_ARGS__) #define IN(T,...) T __VA_ARGS__; READ(__VA_ARGS__) #define LL(...) IN(ll, __VA_ARGS__) #define READVEC(...) internal::READVECnodump(__VA_ARGS__); dump(__VA_ARGS__) #define VEC(T,n,...) vc __VA_ARGS__; READVEC(n, __VA_ARGS__) #define PRINT fastio::print namespace internal { template auto &tuple_add_impl(A &a, const B &b, const index_sequence) { ((get(a) += get(b)), ...); return a; } }; template tuple &operator+=(tuple &a, const Tp &b) { return internal::tuple_add_impl(a, b, make_index_sequence>>{}); } template void offset(vc &v, const Add &add) { for (auto &vi : v) vi += add; } namespace internal { }; // https://github.com/miscalculation53/library/tree/wip/template/template_random.hpp mt19937_64 mt; namespace internal { }; // https://github.com/miscalculation53/library/tree/wip/math/modint/template_modint.hpp // https://github.com/miscalculation53/library/tree/wip/math/modint/modint.hpp // https://github.com/miscalculation53/library/tree/wip/math/modint/modint_internal_static.hpp // https://github.com/miscalculation53/library/tree/wip/utils/larger_int.hpp template struct larger_int { using type = T; }; #define LARGER_INT(T,U) template <> struct larger_int { using type = U; }; LARGER_INT(signed char, short) LARGER_INT(short, int) LARGER_INT(int, long long) LARGER_INT(long, __int128_t) LARGER_INT(long long, __int128_t) LARGER_INT(unsigned char, unsigned short) LARGER_INT(unsigned short, unsigned int) LARGER_INT(unsigned int, unsigned long long) LARGER_INT(unsigned long, __uint128_t) LARGER_INT(unsigned long long, __uint128_t) #undef LARGER_INT template using larger_int_t = typename larger_int::type; // https://github.com/miscalculation53/library/tree/wip/math/modint/modint_internal_isprime.hpp namespace internal { template constexpr ll powmod_constexpr(ll x, ll n, T m) { if (m == 1) return 0; using U = make_unsigned_t; using L = larger_int_t; U r = 1, y = safemod(x, m); while (n) { if (n & 1) r = L(r) * y % m; y = L(y) * y % m; n >>= 1; } return r; } template constexpr bool isprime_constexpr(T n) { if constexpr (sizeof(T) > 4) { if (n <= INT_MAX) return isprime_constexpr(n); } if (n <= 1) return false; if (n == 2 || n == 7 || n == 61) return true; if (n % 2 == 0) return false; ll d = n - 1; while (d % 2 == 0) d /= 2; using U = make_unsigned_t; using L = larger_int_t; auto miller_rabin = [&](const auto &bases) constexpr { for (ll a : bases) { ll t = d, y = powmod_constexpr(a, t, n); while (t != n - 1 && y != 1 && y != n - 1) { y = L(y) * y % n; t <<= 1; } if (y != n - 1 && t % 2 == 0) return false; } return true; }; if constexpr(sizeof(T) <= 4) { constexpr ll bases[3] = {2, 7, 61}; return miller_rabin(bases); } else { constexpr ll bases[7] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; return miller_rabin(bases); } } template constexpr bool isprime = isprime_constexpr(n); }; namespace internal { template struct policy_static { using mod_type = decltype(M); using value_type = make_unsigned_t; using calc_type = larger_int_t; static constexpr bool is_prime = isprime_constexpr(M); static constexpr mod_type mod() { return M; } static constexpr value_type umod() { return M; } static constexpr value_type init(value_type v) { return v; } static constexpr mod_type val(value_type v) { return v; } static constexpr value_type mul(value_type a, value_type b) { return (value_type)((calc_type(a) * b) % M); } }; }; // https://github.com/miscalculation53/library/tree/wip/math/modint/modint_internal_barrett32.hpp namespace internal { struct barrett32 { uint m; ull im; explicit barrett32(uint m) : m(m), im((ull)(-1) / m + 1) {} uint umod() const { return m; } uint mul(uint a, uint b) const { ull z = a; z *= b; ull x = ull((u128(z) * im) >> 64); ull y = x * m; return uint(z - y + (z < y ? m : 0)); } }; template struct policy_barrett32 { using value_type = uint; using calc_type = ull; using mod_type = int; static constexpr bool is_prime = false; static inline barrett32 reducer{998244353}; static mod_type mod() { return reducer.umod(); } static value_type init(value_type v) { return v; } }; }; // https://github.com/miscalculation53/library/tree/wip/math/modint/modint_internal_montgomery64.hpp namespace internal { inline constexpr ull inv64(ull a) { ull x = a; while (a * x != 1) x *= 2 - a * x; return x; } struct montgomery64odd { ull m, im, sq; explicit montgomery64odd(ull m) : m(m), im(inv64(m)), sq(-u128(m) % m) {} ull umod() const { return m; } ull reduce(u128 x) const { auto t = (x + u128(m) * (-im * ull(x))) >> 64; if (t >= m) t -= m; return (ull)t; } ull inv_reduce(i128 v) const { return reduce(u128(v % m + m) * sq); } }; struct montgomery64 { ull m, mx, imx, d, q; uint b; explicit montgomery64(ull m) : m(m) { b = countr_zero(m), mx = m >> b; imx = inv64(mx); d = powmod_constexpr((mx + 1) / 2, b, mx); u128 sq = -u128(mx) % mx; q = (1 + (((sq - 1) * d) << b)) % m; } ull umod() const { return m; } ull reduce(u128 x) const { if (b == 0) { auto t = (x + u128(mx) * (-imx * ull(x))) >> 64; if (t >= m) t -= m; return (ull)t; } ull p = x & MASK(b); x = (x >> b) + p * d; ull y = p << (64 - b); auto t = (x + u128(mx) * (imx * (y - ull(x)))) >> (64 - b); if (t >= m) { t -= m; if (t >= m) t -= m; } return (ull)t; } ull inv_reduce(i128 v) const { return reduce(u128(v % m + m) * q); } }; template struct policy_montgomery64_odd { using value_type = ull; using calc_type = u128; using mod_type = ll; static constexpr bool is_prime = false; static inline montgomery64odd reducer{(1LL << 61) - 1}; static mod_type mod() { return reducer.umod(); } static value_type init(value_type v) { return reducer.inv_reduce(v); } }; template struct policy_montgomery64 { using value_type = ull; using calc_type = u128; using mod_type = ll; static constexpr bool is_prime = false; static inline montgomery64 reducer{(1LL << 61) - 1}; static mod_type mod() { return reducer.umod(); } static value_type init(value_type v) { return reducer.inv_reduce(v); } }; }; // https://github.com/miscalculation53/library/tree/wip/math/extgcd.hpp template constexpr tuple extgcd(T a, T b) { if (a == 0 && b == 0) return {0, 0, 0}; T x1 = 1, y1 = 0, z1 = a; T x2 = 0, y2 = 1, z2 = b; while (z2 != 0) { T q = z1 / z2; tie(x1, x2) = make_pair(x2, x1 - q * x2); tie(y1, y2) = make_pair(y2, y1 - q * y2); tie(z1, z2) = make_pair(z2, z1 - q * z2); } if (z1 < 0) x1 = -x1, y1 = -y1, z1 = -z1; return {z1, x1, y1}; } namespace internal { template struct modint_impl { using V = typename Policy::value_type; using M = typename Policy::mod_type; using mint = modint_impl; private: V _v; public: static constexpr M mod() { return Policy::mod(); } modint_impl() : _v(0) {} template >> modint_impl(T v) { V rem; if constexpr (is_signed_ext) { using S = make_signed_t; S x = v % S(Policy::umod()); if (x < 0) x += Policy::umod(); rem = x; } else rem = V(v % Policy::umod()); _v = Policy::init(rem); }; M val() const { return Policy::val(_v); } mint &operator+=(const mint &rhs) { _v += rhs._v; if (_v >= Policy::umod()) _v -= Policy::umod(); return *this; } mint &operator-=(const mint &rhs) { _v -= rhs._v; if (_v >= Policy::umod()) _v += Policy::umod(); return *this; } mint &operator*=(const mint &rhs) { _v = Policy::mul(_v, rhs._v); return *this; } template mint pow(T n) const { assert(n >= 0); mint x = *this, r = 1; while (n) { if (n & 1) r *= x; x *= x; n >>= 1; } return r; } mint inv() const { if constexpr (Policy::is_prime) { return pow(mod() - 2); } else { auto [g, x, y] = extgcd(val(), mod()); assert(g == 1); return mint(x); } } friend mint operator+(const mint &lhs, const mint &rhs) { return mint(lhs) += rhs; } friend mint operator-(const mint &lhs, const mint &rhs) { return mint(lhs) -= rhs; } friend mint operator*(const mint &lhs, const mint &rhs) { return mint(lhs) *= rhs; } friend mint operator/(const mint &lhs, const mint &rhs) { return mint(lhs) /= rhs; } friend bool operator==(const mint &lhs, const mint &rhs) { return lhs._v == rhs._v; } friend bool operator!=(const mint &lhs, const mint &rhs) { return lhs._v != rhs._v; } friend void rd1(mint &x) { long long a; fastio::rd1(a); x = a; } friend void wt1(const mint &x) { fastio::wt1(x.val()); } }; }; template using static_modint32 = internal::modint_impl>; template using dynamic_modint32 = internal::modint_impl>; template using static_modint64 = internal::modint_impl>; template using dynamic_modint64_odd = internal::modint_impl>; template using dynamic_modint64 = internal::modint_impl>; using modint998244353 = static_modint32<998244353>; template struct is_modint : std::false_type { }; template struct is_modint> : std::true_type { }; template inline constexpr bool is_modint_v = is_modint::value; template struct is_static_modint : false_type {}; template struct is_static_modint> : true_type {}; template struct is_static_modint> : true_type {}; template inline constexpr bool is_static_modint_v = is_static_modint::value; template struct is_dynamic_modint : false_type {}; template struct is_dynamic_modint> : true_type {}; template struct is_dynamic_modint> : true_type {}; template struct is_dynamic_modint> : true_type {}; template inline constexpr bool is_dynamic_modint_v = is_dynamic_modint::value; template struct has_mod : std::false_type { }; template struct has_mod> : std::true_type { }; // https://github.com/miscalculation53/library/tree/wip/math/modint/power_table.hpp // https://github.com/miscalculation53/library/tree/wip/math/modint/binomial.hpp // https://github.com/miscalculation53/library/tree/wip/math/modint/stom.hpp // https://github.com/miscalculation53/library/tree/wip/math/modint/to_rational.hpp // https://github.com/miscalculation53/library/tree/wip/math/svp2d.hpp namespace cpp_dump { struct mint_to_rat_fn { template constexpr auto operator()(const T &x) const -> decltype(mint_to_rat(x)) { return mint_to_rat(x); } }; struct rat_closure : std::ranges::range_adaptor_closure { template constexpr auto operator()(T &&t) const { if constexpr (!std::ranges::range && std::invocable(t))>) { return mint_to_rat_fn{}(std::forward(t)); } else if constexpr (std::ranges::range) { using Ref = std::ranges::range_reference_t; if constexpr (std::invocable(std::declval()))>) { return std::forward(t) | std::views::transform(mint_to_rat_fn{}); } else if constexpr (std::ranges::range) { return std::forward(t) | std::views::transform([this](auto &&inner) { return (*this)(std::forward(inner)); }); } else { static_assert(false); } } else { static_assert(false); } } }; template requires(!std::ranges::range && std::invocable) constexpr rat_closure rat() { return rat_closure{}; } } using mint = modint998244353; void init() { oj(mt.seed(random_device()())); } // https://github.com/miscalculation53/library/tree/wip/graph/sssp.hpp // https://github.com/miscalculation53/library/tree/wip/graph/graph.hpp // https://github.com/miscalculation53/library/tree/wip/ds/csr.hpp template struct CSR { protected: int n, m; vc start; vc elist; vc len; inline int get_last(int i) const { if constexpr (is_erasable) return start[i] + len[i]; else return start[i + 1]; } template struct RowBase { using iterator = Iter; using reference = typename iterator_traits::reference; private: iterator begi, endi; public: RowBase(const iterator &begi, const iterator &endi) : begi(begi), endi(endi) {} inline iterator begin() const { return begi; } inline iterator end() const { return endi; } inline reference operator[](int i) const { return *(begi + i); } }; using Row = RowBase::iterator>; using ConstRow = RowBase::const_iterator>; public: CSR() {} CSR(const vc &row_sizes) : n(row_sizes.size()) { fec(s : row_sizes) assert(s >= 0); start = cumlsum(row_sizes); m = start.back(); elist.resize(m); if constexpr (is_erasable) len = row_sizes; } Row operator[](int i) { return Row(elist.begin() + start[i], elist.begin() + get_last(i)); } ConstRow operator[](int i) const { return ConstRow(elist.begin() + start[i], elist.begin() + get_last(i)); } int offset(int i) const { assert(0 <= i && i <= n); return start[i]; } }; template struct Edge { int from, to; Cost cost; int index; Edge() : from(-1), to(-1), index(-1) {} Edge(int s, int t, Cost c, int i = -1) : from(s), to(t), cost(c), index(i) {} bool operator<(const Edge &rhs) const; }; template struct GraphArc { int to, index; Cost cost; bool operator<(const GraphArc &rhs) const; }; template struct Graph { using E = Edge; using A = GraphArc; protected: using GE = conditional_t; int n = 0, m = 0, era = 0; CSR g; vc eid_to_elist_id; struct OutEdgeIter { using iterator_category = input_iterator_tag; using value_type = E; using reference = const E &; int from; typename vc::const_iterator it; mutable E e; bool operator==(const OutEdgeIter &rhs) const; }; template void build(F input_edge) { vc row_sizes(n); repi(i, m) { auto [u, v, w] = input_edge(i); assert(0 <= u && u < n && 0 <= v && v < n); row_sizes[u]++; if constexpr (!is_directed) if (u != v) row_sizes[v]++; } g = CSR(row_sizes); if constexpr (is_erasable) eid_to_elist_id.assign((is_directed ? 1 : 2) * m, -1); vc cnt(n); repi(i, m) { auto [u, v, w] = input_edge(i); int j = cnt[u]++; int k = g.offset(u) + j; if constexpr (is_erasable) g[u][j] = E(u, v, w, i); else g[u][j] = A{int(v), i, w}; if constexpr (is_erasable) { int id = is_directed ? i : 2 * i + (u <= v); eid_to_elist_id[id] = k; } if constexpr (!is_directed) { if (u != v) { j = cnt[v]++; k = g.offset(v) + j; if constexpr (is_erasable) g[v][j] = E(v, u, w, i); else g[v][j] = A{int(u), i, w}; if constexpr (is_erasable) eid_to_elist_id[2 * i + (v <= u)] = k; } } } } public: template Graph(int n, const vc> &es) : n(n), m(es.size()), era(0) { build(LMD(i, es[i])); } template I size() const { return n; } template I num_of_edges() const { return m - era; } auto out_edges(int v) const; auto out_arcs(int v) const { return g[v]; } vc edges() const; private: }; // https://github.com/miscalculation53/library/tree/wip/ds/my_queue.hpp template struct MyQueue { private: vc d; int pos = 0; public: void reserve(int n); bool empty() const { return pos == SZ(d); } void push(const T &t) { d.eb(t); } T &front() { return d[pos]; } void pop() { pos++; } }; template struct ShortestPath : Graph { using Graph::Graph; using Graph::size; using Graph::num_of_edges; using Graph::out_edges; using Graph::out_arcs; using Graph::edges; private: static constexpr decltype(auto) inf() { return resolved_value(); } vc dists; vc> prv; int source = -1; bool solved_all = false; void init_solve(int s, int t) { source = s; solved_all = (t == -1); } public: vc bfs(int s, int t = -1) { const int n = size(); assert(0 <= s && s < n); init_solve(s, t); dists.assign(n, inf()); prv.assign(n, {}); MyQueue que; dists[s] = 0; que.push(s); while (!que.empty()) { auto v = que.front(); que.pop(); if (v == t) break; fe(e : out_arcs(v)) { if (chmin(dists[e.to], dists[v] + e.cost)) { prv[e.to] = Edge(v, e.to, e.cost, e.index); que.push(e.to); } } } return dists; } vc bfs01(int s, int t = -1) { const int n = size(); assert(0 <= s && s < n); init_solve(s, t); dists.assign(n, inf()); prv.assign(n, {}); vc cur{int(s)}, nxt; vc used(n, false); dists[s] = 0; while (!cur.empty() || !nxt.empty()) { if (cur.empty()) cur.swap(nxt); int v = cur.back(); cur.pop_back(); if (used[v]) continue; used[v] = true; if (v == t) break; fe(e : out_arcs(v)) { if (chmin(dists[e.to], dists[v] + e.cost)) { prv[e.to] = Edge(v, e.to, e.cost, e.index); if (e.cost == 0) cur.eb(e.to); else nxt.eb(e.to); } } } return dists; } vc dial(int s, int max_cost, int t = -1); vc dijkstra(int s, int t = -1) { const int n = size(); assert(0 <= s && s < n); init_solve(s, t); dists.assign(n, inf()); prv.assign(n, {}); pql> pque; dists[s] = 0; pque.push({0, s}); while (!pque.empty()) { auto [d, v] = pque.top(); pque.pop(); if (v == t) break; if (dists[v] != d) continue; fec(e : out_arcs(v)) { Cost nd = dists[v] + e.cost; if (chmin(dists[e.to], nd)) { prv[e.to] = Edge(v, e.to, e.cost, e.index); pque.push({nd, e.to}); } } } return dists; } vc dijkstra_dense(int s, int t = -1) { const int n = size(); assert(0 <= s && s < n); init_solve(s, t); dists.assign(n, inf()); prv.assign(n, {}); vc ok(n, false); dists[s] = 0; repi(_, n) { Cost mn = inf(); int v = -1; repi(u, n) if (!ok[u] && chmin(mn, dists[u])) v = u; if (v == -1) break; if (v == t) break; ok[v] = true; fec(e : out_arcs(v)) { if (chmin(dists[e.to], dists[v] + e.cost)) prv[e.to] = Edge(v, e.to, e.cost, e.index); } } return dists; } vc bellman_ford(int s) { const int n = size(); assert(0 <= s && s < n); init_solve(s, -1); dists.assign(n, inf()); prv.assign(n, {}); dists[s] = 0; repi(t, 2 * n) { repi(v, n) { if (dists[v] == inf()) continue; fec(e : out_arcs(v)) { Cost nd = dists[v] == -inf() ? -inf() : dists[v] + e.cost; if (dists[e.to] > nd) { prv[e.to] = Edge(v, e.to, e.cost, e.index); if (t == n - 1) dists[e.to] = -inf(); else dists[e.to] = nd; } } } } return dists; } vc solve(int s, int t = -1) { bool neg = false; int zcnt = 0; Cost wplus1 = -inf(); Cost max_cost = 0; bool wpluscnt_geq2 = false; repi(v, size()) fec(e : out_arcs(v)) { if (e.cost < 0) { neg = true; break; } chmax(max_cost, e.cost); } repi(v, size()) fec(e : out_arcs(v)) { if (e.cost == 0) zcnt++; if (e.cost > 0) { if (wplus1 < 0) wplus1 = e.cost; else if (wplus1 != e.cost) { wpluscnt_geq2 = true; break; } } } if (neg) return bellman_ford(s); else if (wpluscnt_geq2) { const ll n = size(), m = num_of_edges(); if (n * n < (m << 4)) return dijkstra_dense(s, t); else { if constexpr (is_integral_ext) { const u128 c = u128(max_cost); const ull lg = max(1, bit_width(ull(n)) - 1); if (c < u128(INT_MAX) && u128(n) * c <= u128(m) * lg) return dial(s, int(c), t); } return dijkstra(s, t); } } else { if (zcnt == 0) return bfs(s, t); else return bfs01(s, t); } } }; // https://github.com/miscalculation53/library/tree/wip/math/bigint.hpp // https://github.com/miscalculation53/library/tree/wip/math/convolution/convolution_ll.hpp // https://github.com/miscalculation53/library/tree/wip/math/convolution/convolution.hpp // https://github.com/miscalculation53/library/tree/wip/math/crt.hpp template constexpr tuple crt2(R0 r0_, R1 r1_, M0 m0_, M1 m1_) { T m0 = m0_, m1 = m1_; assert(m0 >= 1 && m1 >= 1); T r0 = safemod(r0_, m0), r1 = safemod(r1_, m1); if (m0 < m1) swap(r0, r1), swap(m0, m1); if (m0 % m1 == 0) { if (r0 % m1 != r1) return {false, 0, 0}; return {true, r0, m0}; } auto [g, im, _] = extgcd(m0, m1); T u1 = m1 / g; if ((r1 - r0) % g) return {false, 0, 0}; T x = (r1 - r0) / g % u1 * im % u1; r0 += x * m0; m0 *= u1; if (r0 < 0) r0 += m0; return {true, r0, m0}; } template constexpr tuple crt(const V1 &rs, const V2 &ms) { assert(rs.size() == ms.size()); const int n = rs.size(); T r = 0, m = 1; repi(i, n) { auto [ok, nr, nm] = crt2(r, rs[i], m, ms[i]); if (!ok) return {false, 0, 0}; r = nr, m = nm; } return {true, r, m}; } namespace internal { constexpr int primitive_root_constexpr(int m) { if (m == 2) return 1; if (m == 167772161) return 3; if (m == 469762049) return 3; if (m == 754974721) return 11; if (m == 998244353) return 3; if (m == 1107296257) return 10; if (m == 1711276033) return 29; if (m == 1811939329) return 13; if (m == 2013265921) return 31; if (m == 2113929217) return 5; int divs[20] = {}; divs[0] = 2; int cnt = 1; int x = (m - 1) / 2; while (x % 2 == 0) x /= 2; for (int i = 3; (long long)(i)*i <= x; i += 2) { if (x % i == 0) { divs[cnt++] = i; while (x % i == 0) { x /= i; } } } if (x > 1) { divs[cnt++] = x; } for (int g = 2;; g++) { bool ok = true; for (int i = 0; i < cnt; i++) { if (powmod_constexpr(g, (m - 1) / divs[i], m) == 1) { ok = false; break; } } if (ok) return g; } } template constexpr int primitive_root_for_convolution = primitive_root_constexpr(m); template > struct fft_info { static constexpr int rank2 = countr_zero(mint::mod() - 1); std::array root; std::array iroot; std::array rate2; std::array irate2; std::array rate3; std::array irate3; fft_info() { root[rank2] = mint(g).pow((mint::mod() - 1) >> rank2); iroot[rank2] = root[rank2].inv(); for (int i = rank2 - 1; i >= 0; i--) { root[i] = root[i + 1] * root[i + 1]; iroot[i] = iroot[i + 1] * iroot[i + 1]; } { mint prod = 1, iprod = 1; for (int i = 0; i <= rank2 - 2; i++) { rate2[i] = root[i + 2] * prod; irate2[i] = iroot[i + 2] * iprod; prod *= iroot[i + 2]; iprod *= root[i + 2]; } } { mint prod = 1, iprod = 1; for (int i = 0; i <= rank2 - 3; i++) { rate3[i] = root[i + 3] * prod; irate3[i] = iroot[i + 3] * iprod; prod *= iroot[i + 3]; iprod *= root[i + 3]; } } } }; } template bool ntt_ok(int n) { if (n <= 0) return false; if constexpr (is_static_modint_v) { if constexpr (!internal::isprime) return false; static constexpr int rank2 = countr_zero(mint::mod() - 1); return n <= (1 << rank2); } else return false; } template void ntt(vc> &) { assert(false); } template void ntt(vc>> &a) { using mint = internal::modint_impl>; int n = int(a.size()); assert(n > 0); int h = countr_zero((unsigned int)n); assert(n == (1 << h)); assert(ntt_ok(n)); static const internal::fft_info info; int len = 0; while (len < h) { if (h - len == 1) { int p = 1 << (h - len - 1); mint rot = 1; for (int s = 0; s < (1 << len); s++) { int offset = s << (h - len); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p] * rot; a[i + offset] = l + r; a[i + offset + p] = l - r; } if (s + 1 != (1 << len)) rot *= info.rate2[countr_zero(~(unsigned int)(s))]; } len++; } else { int p = 1 << (h - len - 2); mint rot = 1, imag = info.root[2]; for (int s = 0; s < (1 << len); s++) { mint rot2 = rot * rot; mint rot3 = rot2 * rot; int offset = s << (h - len); for (int i = 0; i < p; i++) { auto mod2 = 1ULL * mint::mod() * mint::mod(); auto a0 = 1ULL * a[i + offset].val(); auto a1 = 1ULL * a[i + offset + p].val() * rot.val(); auto a2 = 1ULL * a[i + offset + 2 * p].val() * rot2.val(); auto a3 = 1ULL * a[i + offset + 3 * p].val() * rot3.val(); auto a1na3imag = 1ULL * mint(a1 + mod2 - a3).val() * imag.val(); auto na2 = mod2 - a2; a[i + offset] = a0 + a2 + a1 + a3; a[i + offset + 1 * p] = a0 + a2 + (2 * mod2 - (a1 + a3)); a[i + offset + 2 * p] = a0 + na2 + a1na3imag; a[i + offset + 3 * p] = a0 + na2 + (mod2 - a1na3imag); } if (s + 1 != (1 << len)) rot *= info.rate3[countr_zero(~(unsigned int)(s))]; } len += 2; } } } template void intt(vc>> &a) { using mint = internal::modint_impl>; int n = int(a.size()); assert(n > 0); int h = countr_zero((unsigned int)n); assert(n == (1 << h)); assert(ntt_ok(n)); static const internal::fft_info info; int len = h; while (len) { if (len == 1) { int p = 1 << (h - len); mint irot = 1; for (int s = 0; s < (1 << (len - 1)); s++) { int offset = s << (h - len + 1); for (int i = 0; i < p; i++) { auto l = a[i + offset]; auto r = a[i + offset + p]; a[i + offset] = l + r; a[i + offset + p] = ((unsigned long long)mint::mod() + l.val() - (uint)r.val()) * irot.val(); ; } if (s + 1 != (1 << (len - 1))) irot *= info.irate2[countr_zero(~(unsigned int)(s))]; } len--; } else { int p = 1 << (h - len); mint irot = 1, iimag = info.iroot[2]; for (int s = 0; s < (1 << (len - 2)); s++) { mint irot2 = irot * irot; mint irot3 = irot2 * irot; int offset = s << (h - len + 2); for (int i = 0; i < p; i++) { auto a0 = 1ULL * a[i + offset + 0 * p].val(); auto a1 = 1ULL * a[i + offset + 1 * p].val(); auto a2 = 1ULL * a[i + offset + 2 * p].val(); auto a3 = 1ULL * a[i + offset + 3 * p].val(); auto a2na3iimag = 1ULL * mint((mint::mod() + a2 - a3) * iimag.val()).val(); a[i + offset] = a0 + a1 + a2 + a3; a[i + offset + 1 * p] = (a0 + (mint::mod() - a1) + a2na3iimag) * irot.val(); a[i + offset + 2 * p] = (a0 + a1 + (mint::mod() - a2) + (mint::mod() - a3)) * irot2.val(); a[i + offset + 3 * p] = (a0 + (mint::mod() - a1) + (mint::mod() - a2na3iimag)) * irot3.val(); } if (s + 1 != (1 << (len - 2))) irot *= info.irate3[countr_zero(~(unsigned int)(s))]; } len -= 2; } } } namespace internal { template vc convolution_naive(const vc &a, const vc &b) { const int n = a.size(), m = b.size(); const int cnta = n - count(ALL(a), 0), cntb = m - count(ALL(b), 0); vc c(n + m - 1); if ((ll)m * cnta > (ll)n * cntb) { repi(j, m) { if (b[j] == 0) continue; repi(i, n) c[i + j] += a[i] * b[j]; } } else { repi(i, n) { if (a[i] == 0) continue; repi(j, m) c[i + j] += a[i] * b[j]; } } return c; } template vc convolution_ntt(vc a, vc b) { const int n = a.size(), m = b.size(); const int z = bit_ceil(n + m - 1); if (a == b) { a.resize(z); ntt(a); repi(i, z) a[i] *= a[i]; } else { a.resize(z), b.resize(z); ntt(a), ntt(b); repi(i, z) a[i] *= b[i]; } intt(a); mint iz = mint(z).inv(); fem(ai : a) ai *= iz; a.resize(n + m - 1); return a; } template void convolution_crt_helper(const vc &a, const vc &b, vc> &cs) { using mint = static_modint32; const int n = a.size(), m = b.size(); auto c = convolution_ntt(vc(ALL(a)), vc(ALL(b))); repi(i, n + m - 1) cs[i][j] = c[i].val(); } template vc convolution_crt(const vc &a, const vc &b) { const int n = a.size(), m = b.size(); constexpr size_t k = sizeof...(ms); vc> cs(n + m - 1); constexpr array ms_arr = {ms...}; [&](index_sequence) { (convolution_crt_helper(a, b, cs), ...); }(make_index_sequence{}); vc c(n + m - 1); repi(i, n + m - 1) c[i] = get<1>(crt(cs[i], ms_arr)); return c; } } vc convolution_4e18(const vc &a, const vc &b) { if (a.empty() || b.empty()) return {}; const int n = a.size(), m = b.size(); const int cnta = n - count(ALL(a), 0), cntb = m - count(ALL(b), 0); int z = bit_ceil(n + m - 1); ll naive_work = min(ll(cnta) * m, ll(cntb) * n); ll ntt_work = ll(z) * max(1, int(countr_zero((unsigned)z))); if (naive_work <= 18 * ntt_work) return internal::convolution_naive(a, b); return internal::convolution_crt<2013265921, 2113929217>(a, b); } // https://github.com/miscalculation53/library/tree/wip/utils/make_unsigned_ext.hpp template struct make_unsigned_ext { using type = make_unsigned_t; }; template <> struct make_unsigned_ext { using type = u128; }; template using make_unsigned_ext_t = typename make_unsigned_ext::type; template struct make_signed_ext { using type = make_signed_t; }; template <> struct make_signed_ext { using type = i128; }; template struct BigInteger { private: static constexpr int BASE = ipow(base, digit); vl vec; bool is_nega = false; static char digit_to_char(int x) { return x < 10 ? char('0' + x) : char('A' + x - 10); } void zero_suppress() { while (!vec.empty() && vec.back() == 0) vec.pop_back(); if (vec.empty()) is_nega = false; } void carry(int d = -1) { const int n = vec.size(); if (n == 0) return; if (d < 0) d = n - 1; repi(i, d) { vec[i + 1] += vec[i] / BASE; vec[i] = vec[i] % BASE; } for (int i = d; !(0 <= vec[i] && vec[i] < BASE); i++) { vec.eb(vec[i] / BASE); vec[i] = vec[i] % BASE; } } void borrow(int si, int mx) { ll bor = 0; repi(i, si, vec.size()) { ll val = vec[i] - bor; if (val < 0) { bor = (-val + BASE - 1) / BASE; vec[i] = val + bor * BASE; } else { vec[i] = val; bor = 0; if (i >= mx) break; } } if (bor > 0) { is_nega ^= 1; ll car = 1; repi(i, vec.size()) { ll val = (BASE - 1) - vec[i] + car; if (val >= BASE) vec[i] = val - BASE, car = 1; else vec[i] = val, car = 0; } } zero_suppress(); if (vec.empty()) is_nega = false; } BigInteger &operator<<=(size_t k) { vec.insert(vec.begin(), k, 0); return *this; } BigInteger &operator>>=(size_t k) { vec.erase(vec.begin(), vec.begin() + min(vec.size(), k)); return *this; } BigInteger operator<<(size_t k) const { return BigInteger(*this) <<= k; } BigInteger operator>>(size_t k) const { return BigInteger(*this) >>= k; } pair divmod_digit(int d) const { BigInteger q = *this; ll rem = 0; repi(i, SZ(q.vec) - 1, -1, -1) { ll cur = q.vec[i] + rem * BASE; q.vec[i] = cur / d; rem = cur % d; } q.zero_suppress(); return {q, int(rem)}; } pair divmod_knuth(const BigInteger &b) const { BigInteger q, r; vl u = vec, v = b.vec; const ll d = BASE / (v.back() + 1); auto normalize = [&](vl &a) { ll car = 0; fem(x : a) { ll cur = x * d + car; x = cur % BASE, car = cur / BASE; } if (car) a.eb(car); }; normalize(u), normalize(v); const int n = v.size(); u.eb(0); const int m = SZ(u) - n - 1; q.vec.resize(m + 1); repi(j, m, -1, -1) { ll cur = u[j + n] * BASE + u[j + n - 1]; ll x = cur / v[n - 1], rem = cur % v[n - 1]; if (x == BASE) x--, rem += v[n - 1]; while (n >= 2 && rem < BASE && x * v[n - 2] > rem * BASE + u[j + n - 2]) x--, rem += v[n - 1]; ll bor = 0; repi(i, n) { ll z = x * v[i] + bor; bor = z / BASE, z %= BASE; if (u[j + i] < z) u[j + i] += BASE, bor++; u[j + i] -= z; } u[j + n] -= bor; if (u[j + n] < 0) { x--; ll car = 0; repi(i, n) { ll z = u[j + i] + v[i] + car; u[j + i] = z % BASE, car = z / BASE; } u[j + n] += car; } q.vec[j] = x; } r.vec.assign(u.begin(), u.begin() + n); ll rem = 0; repi(i, n - 1, -1, -1) { ll cur = r.vec[i] + rem * BASE; r.vec[i] = cur / d, rem = cur % d; } q.zero_suppress(), r.zero_suppress(); return {q, r}; } pair divmod_abs(const BigInteger &b) const { BigInteger a = abs(), bb = b.abs(); if (a < bb) return {0, a}; ll work = ll(bb.vec.size()) * (SZ(a.vec) - SZ(bb.vec) + 1); if (work <= 600'000) return a.divmod_knuth(bb); BigInteger ib = bb.inv(a.vec.size()); BigInteger q = (a * ib) >> (SZ(a.vec) + SZ(bb.vec) - 1); BigInteger r = a - bb * q; assert(r >= 0); if (r >= bb) q += 1, r -= bb; return {q, r}; } int cmp(const BigInteger &b) const { if (is_nega ^ b.is_nega) return is_nega ? -1 : 1; if (vec.size() != b.vec.size()) return ((vec.size() < b.vec.size()) ^ is_nega) ? -1 : 1; repi(i, SZ(vec) - 1, -1, -1) { if (vec[i] != b.vec[i]) return ((vec[i] < b.vec[i]) ^ is_nega) ? -1 : 1; } return 0; } template void add_abs(int q, T val) { if (q >= SZ(vec)) vec.resize(q + 1); int i = q; while (val > 0) { if (i >= SZ(vec)) vec.eb(0); val += vec[i]; vec[i] = ll(val % BASE); val /= BASE; i++; } } template void sub_abs(int q, T val) { if (q >= SZ(vec)) vec.resize(q + 1); int i = q; while (val > 0) { if (i >= SZ(vec)) vec.eb(0); vec[i] -= ll(val % BASE); val /= BASE; i++; } borrow(q, i - 1); } public: BigInteger() {} template >> BigInteger(T x) { using U = make_unsigned_ext_t; U ux = x; if constexpr (is_signed_ext) { if (x < 0) is_nega = true, ux = -ux; else is_nega = false; } else is_nega = false; if (ux == 0) return; while (ux > 0) { vec.eb((ll)(ux % BASE)); ux /= BASE; } } string to_string() const { const int n = vec.size(); if (n == 0) return "0"; string s; s.reserve(size_t(n) * digit + is_nega); if (is_nega) s += '-'; ll x = vec.back(); char buf[digit]; int len = 0; do { buf[len++] = digit_to_char(x % base); x /= base; } while (x); repi(i, len - 1, -1, -1) s += buf[i]; repi(i, SZ(vec) - 2, -1, -1) { size_t p = s.size(); s.resize(p + digit); x = vec[i]; repi(j, digit - 1, -1, -1) { s[p + j] = digit_to_char(x % base); x /= base; } } return s; } bool operator<(const BigInteger &b) const { return cmp(b) < 0; } bool operator>(const BigInteger &b) const { return cmp(b) > 0; } bool operator>=(const BigInteger &b) const { return cmp(b) >= 0; } bool operator==(const BigInteger &b) const { return is_nega == b.is_nega && vec == b.vec; } bool operator!=(const BigInteger &b) const { return !(*this == b); } BigInteger operator-() const { BigInteger res(*this); if (!res.vec.empty()) res.is_nega ^= 1; return res; } BigInteger abs() const { BigInteger res(*this); res.is_nega = false; return res; } BigInteger &operator+=(const BigInteger &b) { if (b.vec.empty()) return *this; if (vec.size() < b.vec.size()) vec.resize(b.vec.size()); if (is_nega == b.is_nega) { repi(i, b.vec.size()) vec[i] += b.vec[i]; carry(); } else { repi(i, b.vec.size()) vec[i] -= b.vec[i]; borrow(0, SZ(b.vec) - 1); } return *this; } BigInteger &operator-=(const BigInteger &b) { if (b.vec.empty()) return *this; if (vec.size() < b.vec.size()) vec.resize(b.vec.size()); if (is_nega != b.is_nega) { repi(i, b.vec.size()) vec[i] += b.vec[i]; carry(); } else { repi(i, b.vec.size()) vec[i] -= b.vec[i]; borrow(0, SZ(b.vec) - 1); } return *this; } BigInteger &operator*=(const BigInteger &b) { if (this->vec.empty() || b.vec.empty()) { this->vec.clear(); this->is_nega = false; return *this; } bool neg = is_nega ^ b.is_nega; if (b.vec.size() == 1) { *this *= int(b.vec[0]); is_nega = neg; return *this; } if (vec.size() == 1) { int v = vec[0]; *this = b; *this *= v; is_nega = neg; return *this; } vec = convolution_4e18(this->vec, b.vec); carry(); zero_suppress(); is_nega = neg; return *this; } BigInteger operator+(const BigInteger &b) const { return BigInteger(*this) += b; } BigInteger operator-(const BigInteger &b) const { return BigInteger(*this) -= b; } BigInteger operator*(const BigInteger &b) const { return BigInteger(*this) *= b; } BigInteger inv(int d) const { assert(!vec.empty()); BigInteger a(abs()), c, c2; BigInteger b = binsearch(LMD(m, ((a * m).vec.size() <= a.vec.size())), 0, BASE + 1, false, false).first; const BigInteger ONE(1), TWO(2); for (int k = 1;; k = min(2 * k, d)) { c = a * b; if (SZ(b.vec) >= d + 1 && SZ(c.vec) == SZ(a.vec) + SZ(b.vec) - 1) { c2 = c + a; if (c2.vec.size() == a.vec.size() + b.vec.size()) { if (c2 == ONE << (SZ(c2.vec) - 1)) b += 1; break; } } b *= (TWO << (SZ(a.vec) + SZ(b.vec) - 1)) - c; if (SZ(b.vec) >= k + 1) b >>= SZ(b.vec) - k - 1; } b >>= 1; if (is_nega) b = -b; return b; } BigInteger operator/(const BigInteger &b) const { assert(!b.vec.empty()); if (b.vec.size() == 1) { BigInteger q = divmod_digit(int(b.vec[0])).first; q.is_nega = !q.vec.empty() && (is_nega ^ b.is_nega); return q; } BigInteger q = divmod_abs(b).first; q.is_nega = !q.vec.empty() && (is_nega ^ b.is_nega); return q; } pair divmod(const BigInteger &b) const { assert(!b.vec.empty()); if (b.vec.size() == 1) { auto [q, rem] = divmod_digit(int(b.vec[0])); q.is_nega = !q.vec.empty() && (is_nega ^ b.is_nega); BigInteger r(rem); r.is_nega = rem && is_nega; return {q, r}; } auto [q, r] = divmod_abs(b); q.is_nega = !q.vec.empty() && (is_nega ^ b.is_nega); r.is_nega = !r.vec.empty() && is_nega; return {q, r}; } BigInteger operator%(const BigInteger &b) const { return divmod(b).second; } BigInteger &operator%=(const BigInteger &b) { return *this = *this % b; } template >> BigInteger &operator+=(T v) { if (v == 0) return *this; bool v_nega = false; using U = make_unsigned_ext_t; U uv = v; if constexpr (is_signed_ext) { if (v < 0) v_nega = true, uv = -uv; } using V = larger_int_t; if (is_nega == v_nega) add_abs(0, (V)uv); else sub_abs(0, (V)uv); return *this; } template >> BigInteger &operator*=(T v) { if (vec.empty() || v == 0) { vec.clear(); is_nega = false; return *this; } bool v_nega = false; using U = make_unsigned_ext_t; U uv = v; if constexpr (is_signed_ext) { if (v < 0) v_nega = true, uv = -uv; } is_nega ^= v_nega; using V = larger_int_t; V car = 0; repi(i, SZ(vec)) { car += (V)vec[i] * uv; vec[i] = (ll)(car % BASE); car /= BASE; } while (car > 0) { vec.eb((ll)(car % BASE)); car /= BASE; } return *this; } template >> BigInteger &operator/=(T v) { assert(v != 0); if (vec.empty()) return *this; bool v_nega = false; using U = make_unsigned_ext_t; U uv = v; if constexpr (is_signed_ext) { if (v < 0) v_nega = true, uv = -uv; } is_nega ^= v_nega; using V = larger_int_t; V rem = 0; repi(i, SZ(vec) - 1, -1, -1) { V cur = vec[i] + rem * BASE; vec[i] = (ll)(cur / uv); rem = cur % uv; } zero_suppress(); return *this; } // base**i * coef を加算、ならし O(1) 時間 // base**i * coef を減算、数が常に非負の場合はならし O(1) 時間 template >> BigInteger operator*(T v) const { return BigInteger(*this) *= v; } template >> BigInteger operator/(T v) const { return BigInteger(*this) /= v; } }; template >> BigInteger operator*(T a, const BigInteger &b) { return b * a; } template BigInteger gcd(BigInteger a, BigInteger b) { a = a.abs(), b = b.abs(); while (b != 0) { a %= b; swap(a, b); } return a; } template BigInteger lcm(BigInteger a, BigInteger b) { if (a == 0 || b == 0) return 0; a = a.abs(), b = b.abs(); return a / gcd(a, b) * b; } template , int> = 0> BigInteger lcm(BigInteger a, T b) { return lcm(move(a), BigInteger(b)); } template , int> = 0> BigInteger lcm(T a, BigInteger b) { return lcm(BigInteger(a), move(b)); } template void wt1(const BigInteger &a) { fastio::wt1(a.to_string()); } // https://github.com/miscalculation53/library/tree/wip/math/rational.hpp /** * @brief 約分しない有理数 * @docs docs/math/rational.md */ template struct is_rational_ordered : false_type {}; template struct is_rational_ordered() < declval())>> : true_type {}; template inline constexpr bool is_rational_ordered_v = is_rational_ordered::value; template struct rational_has_mod : false_type {}; template struct rational_has_mod() % declval())>> : true_type {}; template struct Rational { using value_type = T; T num, den; private: public: bool is_infinite() const; pair reduced() const; friend Rational operator+(Rational lhs, const Rational &rhs) { return lhs += rhs; } friend Rational operator-(Rational lhs, const Rational &rhs) { return lhs -= rhs; } friend Rational operator*(Rational lhs, const Rational &rhs) { return lhs *= rhs; } friend Rational operator/(Rational lhs, const Rational &rhs) { return lhs /= rhs; } friend bool operator==(const Rational &lhs, const Rational &rhs) { if (lhs.is_infinite() || rhs.is_infinite()) return lhs.is_infinite() && rhs.is_infinite() && lhs.num == rhs.num; using C = larger_int_t; return C(lhs.num) * C(rhs.den) == C(rhs.num) * C(lhs.den); } friend bool operator!=(const Rational &lhs, const Rational &rhs) { return !(lhs == rhs); } template , int> = 0> friend bool operator<(const Rational &lhs, const Rational &rhs) { if (lhs.is_infinite() || rhs.is_infinite()) { if (lhs.is_infinite() && rhs.is_infinite()) return lhs.num < rhs.num; if (lhs.is_infinite()) return lhs.num < T(0); return T(0) < rhs.num; } using C = larger_int_t; return C(lhs.num) * C(rhs.den) < C(rhs.num) * C(lhs.den); } template , int> = 0> friend bool operator>(const Rational &lhs, const Rational &rhs) { return rhs < lhs; } template , int> = 0> friend bool operator<=(const Rational &lhs, const Rational &rhs) { return !(rhs < lhs); } template , int> = 0> friend bool operator>=(const Rational &lhs, const Rational &rhs) { return !(lhs < rhs); } friend ostream &operator<<(ostream &os, const Rational &x) { auto [num, den] = x.reduced(); return os << num << '/' << den; } friend void wt1(const Rational &x) { auto [num, den] = x.reduced(); using fastio::wt1; wt1(num), wt1('/'), wt1(den); } }; template struct is_rational : false_type {}; template struct is_rational> : true_type {}; template inline constexpr bool is_rational_v = is_rational::value; namespace std { template struct numeric_limits<::Rational> : numeric_limits { static constexpr bool is_specialized = numeric_limits::is_specialized; static constexpr bool has_infinity = ::is_rational_ordered_v; static constexpr bool is_signed = numeric_limits::is_signed; static constexpr bool is_integer = false; static constexpr bool is_exact = numeric_limits::is_exact; }; } // namespace std void main2() { static const BigInteger L = []() { BigInteger L = 1; rep(i, 1, 300) L = lcm(L, i); return L; }(); dump(L); LL(N, M); VEC(tllll, M, UVAB); offset(UVAB, tllll{-1, -1, 0, 0}); vc>> UVW; fec([ u, v, a, b ] : UVAB) UVW.eb(u, v, a * (L / b)); ShortestPath, []() { return L * 300 * 30000; }> G(N, UVW); auto res = G.solve(0); rep(i, 1, N) { auto num = res[i], den = L; auto g = gcd(num, den); PRINT(num / g, den / g); } } void test() { } // https://github.com/miscalculation53/library/tree/wip/template/template_main.hpp template struct Main { Main() { cauto CERR = [](string val, string color) { string s = "\033[" + color + "m" + val + "\033[m"; /* コードテストで確認する際にコメントアウトを外す cerr << val; //*/ }; CERR("\n[FAST_IO]\n\n", "32"); cout << fixed << setprecision(20); init(); CERR("\n[SINGLE_TESTCASE]\n\n", "36"); main2(); } }; Main main_dummy; int main() {}