#line 1 "lib/components/fast_io.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__unix__) || defined(__APPLE__) #include #include #include #endif namespace fast_io_detail { struct BulkInput; struct BulkOutput; } class FastInput { friend struct fast_io_detail::BulkInput; static constexpr std::size_t capacity = 1 << 16; FILE *file = nullptr; std::unique_ptr buffer; const char *current = "", *end = current; std::string scratch; void *mapping = nullptr; std::size_t mapped_size = 0; bool refill() { if (!file) return false; std::size_t n = std::fread(buffer.get(), 1, capacity, file); current = buffer.get(); end = current + n; return n; } static const char *scan(const char *p, const char *end) { while (end - p >= 8) { std::uint64_t x; std::memcpy(&x, p, 8); if ((x - 0x2121212121212121ULL) & ~x & 0x8080808080808080ULL) break; p += 8; } while (p != end && static_cast(*p) > ' ') ++p; return p; } public: explicit FastInput(FILE *input = stdin) { #if defined(__unix__) || defined(__APPLE__) struct stat status; int fd = fileno(input); auto offset = ftello(input); if (fd >= 0 && offset >= 0 && !fstat(fd, &status) && S_ISREG(status.st_mode) && status.st_size > offset) { mapped_size = status.st_size; mapping = mmap(nullptr, mapped_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping != MAP_FAILED) { current = static_cast(mapping) + offset; end = static_cast(mapping) + mapped_size; return; } mapping = nullptr; } #endif file = input; buffer = std::make_unique_for_overwrite(capacity); } explicit FastInput(std::string_view input) : current(input.empty() ? "" : input.data()), end(current + input.size()) {} FastInput(const FastInput &) = delete; FastInput &operator=(const FastInput &) = delete; ~FastInput() { #if defined(__unix__) || defined(__APPLE__) if (mapping) munmap(mapping, mapped_size); #endif } std::string_view token() { while (true) { while (current != end && static_cast(*current) <= ' ') ++current; if (current != end) break; if (!refill()) return {}; } const char *begin = current; current = scan(current, end); if (current != end || !file) return {begin, std::size_t(current - begin)}; scratch.assign(begin, end); while (refill()) { current = scan(current, end); scratch.append(buffer.get(), std::size_t(current - buffer.get())); if (current != end) break; } return scratch; } template bool read(T &value) { if constexpr (std::is_integral_v && !std::is_same_v) { while (true) { while (current != end && static_cast(*current) <= ' ') ++current; if (current != end) break; if (!refill()) return false; } if constexpr (std::is_unsigned_v && sizeof(T) == 4 && std::endian::native == std::endian::little) { if (end - current >= 11) { std::uint64_t x; std::memcpy(&x, current, 8); if (!(((x + 0x4646464646464646ULL) | (x - 0x3030303030303030ULL)) & 0x8080808080808080ULL)) { x &= 0x0f0f0f0f0f0f0f0fULL; x = (x * 10 + (x >> 8)) & 0x00ff00ff00ff00ffULL; x = (x * 100 + (x >> 16)) & 0x0000ffff0000ffffULL; std::uint64_t v = std::uint32_t(x * 10000 + (x >> 32)); int n = 8; for (; n < 10 && static_cast(current[n]) - unsigned('0') < 10; ++n) v = v * 10 + (current[n] - '0'); if (static_cast(current[n]) <= ' ' && v <= 0xffffffffULL) { current += n; value = T(v); return true; } } } } T parsed{}; auto result = std::from_chars(current, end, parsed); if (result.ec == std::errc{} && (result.ptr != end ? static_cast(*result.ptr) <= ' ' : !file)) { current = result.ptr; value = parsed; return true; } } auto s = token(); if (s.empty()) return false; if constexpr (std::is_same_v) { assert(s == "0" || s == "1"); value = s[0] == '1'; } else if constexpr (std::is_integral_v) { auto result = std::from_chars(s.data(), s.data() + s.size(), value); assert(result.ec == std::errc{} && result.ptr == s.data() + s.size()); (void)result; } else value = T(s); return true; } }; class FastOutput { friend struct fast_io_detail::BulkOutput; inline static constexpr auto quads = [] { std::array, 10000> table{}; for (int i = 0; i < 10000; ++i) table[i] = {char('0' + i / 1000), char('0' + i / 100 % 10), char('0' + i / 10 % 10), char('0' + i % 10)}; return table; }(); FILE *file; std::unique_ptr buffer = std::make_unique_for_overwrite(1 << 16); std::size_t capacity = 1 << 16, length = 0; char *reserve(std::size_t n) { if (n > capacity - length) { if (!flush()) throw std::runtime_error("output failed"); if (n > capacity) { std::size_t next = std::max(n, 2 * capacity); buffer = std::make_unique_for_overwrite(next); capacity = next; } } return buffer.get() + length; } public: explicit FastOutput(FILE *output = stdout) : file(output) {} FastOutput(const FastOutput &) = delete; FastOutput &operator=(const FastOutput &) = delete; ~FastOutput() { flush(); } bool flush() { std::size_t offset = 0; while (offset < length) { auto n = std::fwrite(buffer.get() + offset, 1, length - offset, file); if (!n) { std::memmove(buffer.get(), buffer.get() + offset, length - offset); length -= offset; return false; } offset += n; } length = 0; return std::fflush(file) == 0; } void write(char c) { *reserve(1) = c; ++length; } void write(__uint128_t value) { char digits[40]; char *end = digits + sizeof(digits), *begin = end; do { *--begin = char('0' + value % 10); value /= 10; } while (value); write(std::string_view(begin, end - begin)); } void write(__int128_t value) { __uint128_t magnitude = __uint128_t(value); if (value < 0) write('-'), magnitude = 0 - magnitude; write(magnitude); } void write(std::string_view s) { char *out = reserve(s.size()); if (!s.empty()) std::memcpy(out, s.data(), s.size()); length += s.size(); } template requires std::is_integral_v void write(T value) { char *out = reserve(32); if constexpr (std::is_same_v) *out = '0' + value, ++length; else if constexpr (std::is_unsigned_v && sizeof(T) == 4) { char *p = out; if (value >= 100000000) { auto high = value / 100000000, low = value % 100000000; p = std::to_chars(p, p + 2, high).ptr; std::memcpy(p, quads[low / 10000].data(), 4); std::memcpy(p + 4, quads[low % 10000].data(), 4); p += 8; } else if (value >= 10000) { p = std::to_chars(p, p + 4, value / 10000).ptr; std::memcpy(p, quads[value % 10000].data(), 4); p += 4; } else p = std::to_chars(p, p + 4, value).ptr; length += p - out; } else length += std::to_chars(out, out + 32, value).ptr - out; } template requires requires(const T &value, char *out) { value.decimal_capacity(); value.to_chars(out); } void write(const T &value) { char *out = reserve(value.decimal_capacity()); length += value.to_chars(out) - out; } template void println(const T &value) { write(value); write('\n'); } }; #line 1 "lib/math/floor_sum/generalized_floor_sum.hpp" #line 7 "lib/math/floor_sum/generalized_floor_sum.hpp" #include namespace generalized_floor_sum_detail { using U = std::uint64_t; template constexpr bool integer = std::is_integral_v || std::is_same_v || std::is_same_v; template T divide(T value) { if constexpr (integer) return value / T(N); else { static const T inverse = T(1) / T(N); return value * inverse; } } template using Table = std::array, D + 1>; template struct Coefficients { std::array, D + 1> sums{}; std::array, D + 2> choose{}; std::array denominator{}, inverse{}; Coefficients() { for (int i = 0; i <= D + 1; ++i) { choose[i][0] = choose[i][i] = T(1); for (int j = 1; j < i; ++j) choose[i][j] = choose[i - 1][j - 1] + choose[i - 1][j]; } T factorial = 1; for (int p = 0; p <= D; ++p) { denominator[p] = factorial * T(p + 1); for (int k = 0; k <= p + 1; ++k) { T value = factorial * choose[p + 1][k]; for (int j = 0; j < p; ++j) if (k <= j + 1) value -= factorial / denominator[j] * choose[p + 1][j] * sums[j][k]; sums[p][k] = value; } factorial = denominator[p]; if constexpr (!integer) inverse[p] = T(1) / denominator[p]; } } T divide(T value, int p) const { if constexpr (integer) return value / denominator[p]; else return value * inverse[p]; } }; template const Coefficients &coefficients() { static const Coefficients value; return value; } template [[gnu::always_inline]] inline void translate(Table &result, const Coefficients &c, A a, B b, std::array &ak, std::array &bk) { if (a != A(0)) { ak[0] = T(1); for (int i = 1; i <= D; ++i) ak[i] = ak[i - 1] * T(a); for (int q = D; q >= 1; --q) for (int p = 0; p + q <= D; ++p) for (int j = 0; j < q; ++j) result[p][q] += c.choose[q][j] * ak[q - j] * result[p + q - j][j]; } if (b != B(0)) { bk[0] = T(1); for (int i = 1; i <= D; ++i) bk[i] = bk[i - 1] * T(b); for (int q = D; q >= 1; --q) for (int p = 0; p + q <= D; ++p) for (int j = 0; j < q; ++j) result[p][q] += c.choose[q][j] * bk[q - j] * result[p][j]; } } template Table euclidean(U n, U m, U a, U b) { Table result{}; if (!n) return result; if (n == 1) { result[0][0] = T(1); T value = T(b / m); for (int q = 1; q <= D; ++q) result[0][q] = result[0][q - 1] * value; return result; } const auto &c = coefficients(); std::array sums{}, ak{}, bk{}, kp{}; T x = T(n - 1); for (int p = 0; p <= D; ++p) { T value = c.sums[p][p + 1]; for (int j = p; j >= 0; --j) value = value * x + c.sums[p][j]; sums[p] = c.divide(value, p); } U u = a / m, v = b / m; a %= m; b %= m; if (a) { __uint128_t z = __uint128_t(a) * (n - 1) + b; U k = z >> 64 ? U(z / m) : U(z) / m; if (k) { auto child = euclidean(k, a, m, m - b - 1); kp[0] = T(1); for (int j = 1; j <= D; ++j) kp[j] = kp[j - 1] * T(k); for (int p = 0; p < D; ++p) { std::array inner{}; for (int i = 0; i < D - p; ++i) { T value = 0; for (int j = 0; j <= p + 1; ++j) value += c.sums[p][j] * child[i][j]; inner[i] = c.divide(value, p); } for (int q = 1; p + q <= D; ++q) { T value = sums[p] * kp[q]; for (int i = 0; i < q; ++i) value -= c.choose[q][i] * inner[i]; result[p][q] = value; } } } } for (int p = 0; p <= D; ++p) result[p][0] = sums[p]; translate(result, c, u, v, ak, bk); return result; } template using Signed = std::enable_if_t && std::is_integral_v && (std::is_signed_v || std::is_signed_v), int>; template bool negative(A value) { if constexpr (std::is_signed_v) return value < 0; else return false; } template std::pair normalize(A value, U m) { U x = static_cast(value); if (!negative(value)) return {x % m, T(x / m)}; x = U(0) - x; U r = x % m, q = x / m + (r != 0); if constexpr (integer) return {r ? m - r : 0, T(-__int128_t(q))}; else return {r ? m - r : 0, -T(q)}; } template auto quadratic(U n, U m, U a, U b) { std::conditional_t, std::array> result{}; if (!n) return result; T count = T(n), s1 = T(n >> 1) * T(n - 1 + (n & 1)), s2 = divide<3>(s1 * (T(2) * count - T(1))); U u = a / m, v = b / m; a %= m; b %= m; T f = 0, g = 0, h = 0; if (a) { __uint128_t z = __uint128_t(a) * (n - 1) + b; U k = z >> 64 ? U(z / m) : U(z) / m; if (k) { auto child = quadratic(k, a, m, m - b - 1); T height = T(k); f = T(n - 1) * height - child[0]; g = s1 * height - divide<2>(child[2] + child[0]); h = T(n - 1) * height * height - child[0] - T(2) * child[1]; } } T at = T(u), bt = T(v); T f0 = f + at * s1 + bt * count; T f1 = g + at * s2 + bt * s1; T f2 = h + T(2) * (at * g + bt * f) + at * at * s2 + bt * (T(2) * at * s1 + bt * count); if constexpr (Full) { result[0][0] = count; result[1][0] = s1; result[2][0] = s2; result[0][1] = f0; result[1][1] = f1; result[0][2] = f2; } else result = {f0, f1, f2}; return result; } template T linear(U n, U m, U a, U b) { T result = 0; for (;;) { if (!n) return result; if (n == 1) return result + T(b / m); if (a >= m) result += divide<2>(T(n) * T(n - 1)) * T(a / m), a %= m; if (b >= m) result += T(n) * T(b / m), b %= m; __uint128_t z = __uint128_t(a) * n + b; if (z < m) return result; if (z >> 64) n = z / m, b = z % m; else { U value = z; n = value / m; b = value % m; } std::swap(a, m); } } } template auto generalized_floor_sum_moments(std::uint64_t n, std::uint64_t m, std::uint64_t a, std::uint64_t b) { static_assert(D >= 0); assert(m > 0); if constexpr (D == 0) return generalized_floor_sum_detail::Table<0, T>{std::array{T(n)}}; else if constexpr (D == 1) { generalized_floor_sum_detail::Table<1, T> result{}; result[0][0] = T(n); result[1][0] = n ? generalized_floor_sum_detail::divide<2>(T(n) * T(n - 1)) : T(0); result[0][1] = generalized_floor_sum_detail::linear(n, m, a, b); return result; } else if constexpr (D == 2) return generalized_floor_sum_detail::quadratic(n, m, a, b); else return generalized_floor_sum_detail::euclidean(n, m, a, b); } template T generalized_floor_sum(std::uint64_t n, std::uint64_t m, std::uint64_t a, std::uint64_t b) { static_assert(P >= 0 && Q >= 0); assert(m > 0); if constexpr (Q == 0) { if (!n) return T(0); if constexpr (P == 0) return T(n); else if constexpr (P == 1) return generalized_floor_sum_detail::divide<2>(T(n) * T(n - 1)); else if constexpr (P == 2) return generalized_floor_sum_detail::divide<6>(T(n) * T(n - 1) * (T(2) * T(n) - T(1))); else { const auto &c = generalized_floor_sum_detail::coefficients(); T value = c.sums[P][P + 1], x = T(n - 1); for (int j = P; j >= 0; --j) value = value * x + c.sums[P][j]; return c.divide(value, P); } } else if constexpr (P == 0 && Q == 1) return generalized_floor_sum_detail::linear(n, m, a, b); else return generalized_floor_sum_moments

(n, m, a, b)[P][Q]; } template = 0> auto generalized_floor_sum_moments(std::uint64_t n, std::uint64_t m, A a, B b) { using namespace generalized_floor_sum_detail; static_assert(D >= 0); assert(m > 0); if (!negative(a) && !negative(b)) return generalized_floor_sum_moments(n, m, U(a), U(b)); if constexpr (D == 0) return generalized_floor_sum_moments<0, T>(n, m, U(0), U(0)); else { if (!n) return Table{}; auto [rb, v] = normalize(b, m); if (n == 1) { Table result{}; result[0][0] = T(1); for (int q = 1; q <= D; ++q) result[0][q] = result[0][q - 1] * v; return result; } auto [ra, u] = normalize(a, m); auto result = generalized_floor_sum_moments(n, m, ra, rb); std::array ak{}, bk{}; translate(result, coefficients(), u, v, ak, bk); return result; } } template = 0> T generalized_floor_sum(std::uint64_t n, std::uint64_t m, A a, B b) { using namespace generalized_floor_sum_detail; static_assert(P >= 0 && Q >= 0); assert(m > 0); if constexpr (Q == 0) return generalized_floor_sum(n, m, U(0), U(0)); else { if (!negative(a) && !negative(b)) return generalized_floor_sum(n, m, U(a), U(b)); return generalized_floor_sum_moments

(n, m, a, b)[P][Q]; } } #line 1 "lib/math/mint.hpp" #line 4 "lib/math/mint.hpp" #include #include #line 7 "lib/math/mint.hpp" #if defined(__GNUC__) && !defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) #pragma GCC push_options #pragma GCC optimize("O3") #endif namespace fps_detail { template constexpr bool mint_integral = std::is_integral_v #if defined(__SIZEOF_INT128__) || std::is_same_v || std::is_same_v #endif ; struct Mint { using mint = Mint; unsigned v = 0; static constexpr unsigned mod() { return 998244353; } static unsigned reduce(unsigned long long x) { return (x + (unsigned long long)(unsigned(x) * 998244351u) * mod()) >> 32; } [[gnu::always_inline]] Mint() = default; template , int> = 0> Mint(I x) { long long r = x % (long long)mod(); if (r < 0) r += mod(); v = reduce((unsigned long long)r * 932051910); } static Mint raw(unsigned x) { Mint a; a.v = reduce((unsigned long long)x * 932051910); return a; } static Mint word(unsigned x) { Mint a; a.v = x; return a; } unsigned val() const { unsigned r = reduce(v); return r < mod() ? r : r - mod(); } friend std::istream &operator>>(std::istream &is, Mint &x) { long long value; if (is >> value) x = Mint(value); return is; } friend std::ostream &operator<<(std::ostream &os, const Mint &x) { return os << x.val(); } Mint &operator+=(Mint b) { v += b.v; if (v >= 2 * mod()) v -= 2 * mod(); return *this; } Mint &operator-=(Mint b) { v -= b.v; if (v >> 31) v += 2 * mod(); return *this; } Mint &operator*=(Mint b) { v = reduce((unsigned long long)v * b.v); return *this; } Mint &operator/=(Mint b) { return *this *= b.inv(); } Mint &operator++() { return *this += Mint(1); } Mint &operator--() { return *this -= Mint(1); } Mint operator++(int) { Mint a = *this; ++*this; return a; } Mint operator--(int) { Mint a = *this; --*this; return a; } Mint operator+() const { return *this; } Mint operator-() const { return word(v ? 2 * mod() - v : 0); } Mint operator+(Mint b) const { return Mint(*this) += b; } Mint operator-(Mint b) const { return Mint(*this) -= b; } Mint operator*(Mint b) const { return Mint(*this) *= b; } Mint operator/(Mint b) const { return Mint(*this) /= b; } bool operator==(Mint b) const { return (v < mod() ? v : v - mod()) == (b.v < mod() ? b.v : b.v - mod()); } bool operator!=(Mint b) const { return !(*this == b); } template , int> = 0> friend Mint operator+(I a, Mint b) { return Mint(a) + b; } template , int> = 0> friend Mint operator-(I a, Mint b) { return Mint(a) - b; } template , int> = 0> friend Mint operator*(I a, Mint b) { return Mint(a) * b; } template , int> = 0> friend Mint operator/(I a, Mint b) { return Mint(a) / b; } template , int> = 0> friend bool operator==(I a, Mint b) { return Mint(a) == b; } template , int> = 0> friend bool operator!=(I a, Mint b) { return Mint(a) != b; } Mint pow(long long n) const { assert(n >= 0); if (!n) return Mint(1); Mint r(1), a = *this; for (; n > 1; n >>= 1, a *= a) if (n & 1) r *= a; return r * a; } [[gnu::noinline]] Mint inv() const { assert(*this != Mint(0)); Mint a2 = *this * *this, a3 = a2 * *this; Mint a7 = a3 * a3 * *this; Mint a31 = a7; for (int i = 0; i < 2; ++i) a31 *= a31; a31 *= a3; Mint r = a7; for (int i = 0; i < 3; ++i) r *= r; r *= a3; r *= r; for (int j = 0; j < 4; ++j) { for (int i = 0; i < 5; ++i) r *= r; r *= a31; } for (int i = 0; i < 3; ++i) r *= r; return r * a7; } }; } // namespace fps_detail using fps_mint = fps_detail::Mint; using mint = fps_mint; #if defined(__GNUC__) && !defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) #pragma GCC pop_options #endif #line 4 "b.cpp" template mint solve(int p, int q, std::int64_t n, std::int64_t m, std::int64_t a, std::int64_t b) { auto sums = generalized_floor_sum_moments(n + 1, m, a, b); return sums[p][q]; } int main() { FastInput in; FastOutput out; int t = 0; in.read(t); while (t--) { int p = 0, q = 0; std::int64_t n = 0, m = 1, a = 0, b = 0; in.read(p); in.read(q); in.read(n); in.read(m); in.read(a); in.read(b); auto result = p <= 2 && q <= 2 ? solve<4>(p, q, n, m, a, b) : solve<20>(p, q, n, m, a, b); out.println(result.val()); } }