m1une's library

This documentation is automatically generated by online-judge-tools/verification-helper

View on GitHub

:heavy_check_mark: verify/math/math_algorithms.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"

#include <algorithm>
#include <cassert>
#include <cstdint>
#include "../../utilities/fast_io.hpp"
#include <numeric>
#include <utility>
#include <vector>

#include "../../math/all.hpp"

long long floor_div(long long numerator, long long denominator) {
    long long quotient = numerator / denominator;
    if (numerator % denominator < 0) quotient--;
    return quotient;
}

void test_number_theory() {
    using m1une::math::crt;
    using m1une::math::floor_sum;
    using m1une::math::inv_gcd;
    using m1une::math::inv_mod;
    using m1une::math::pow_mod;

    assert(pow_mod(-2, 5, 13) == 7);
    assert(pow_mod(123, 0, 1) == 0);
    assert(inv_mod(3, 11) == 4);

    const auto inverse = inv_gcd(6, 15);
    assert(inverse.first == 3);
    assert((6 * inverse.second - inverse.first) % 15 == 0);

    const auto solution = crt(
        std::vector<long long>{2, 3, 2},
        std::vector<long long>{3, 5, 7}
    );
    assert(solution.first == 23);
    assert(solution.second == 105);
    const auto inconsistent = crt(
        std::vector<long long>{0, 1},
        std::vector<long long>{2, 4}
    );
    assert(inconsistent.second == 0);

    for (long long first_mod = 1; first_mod <= 12; first_mod++) {
        for (long long second_mod = 1; second_mod <= 12; second_mod++) {
            const long long combined_mod = std::lcm(first_mod, second_mod);
            for (long long first_remainder = -5; first_remainder <= 5;
                 first_remainder++) {
                for (long long second_remainder = -5; second_remainder <= 5;
                     second_remainder++) {
                    long long expected = -1;
                    for (long long value = 0; value < combined_mod; value++) {
                        if (
                            (value - first_remainder) % first_mod == 0 &&
                            (value - second_remainder) % second_mod == 0
                        ) {
                            expected = value;
                            break;
                        }
                    }
                    const auto actual = crt(
                        std::vector<long long>{first_remainder, second_remainder},
                        std::vector<long long>{first_mod, second_mod}
                    );
                    if (expected == -1) {
                        assert(actual.second == 0);
                    } else {
                        assert(actual.first == expected);
                        assert(actual.second == combined_mod);
                    }
                }
            }
        }
    }

    for (long long n = 0; n <= 15; n++) {
        for (long long mod = 1; mod <= 15; mod++) {
            for (long long a = -15; a <= 15; a++) {
                for (long long b = -15; b <= 15; b++) {
                    long long expected = 0;
                    for (long long i = 0; i < n; i++) {
                        expected += floor_div(a * i + b, mod);
                    }
                    assert(floor_sum(n, mod, a, b) == expected);
                }
            }
        }
    }
}

void test_prime_sieve() {
    m1une::math::PrimeSieve sieve(100);
    assert(sieve.primes().size() == 25);
    assert(sieve.is_prime(97));
    assert(!sieve.is_prime(1));
    assert(sieve.min_prime_factor(91) == 7);

    std::vector<std::pair<int, int>> factors_72;
    factors_72.emplace_back(2, 3);
    factors_72.emplace_back(3, 2);
    assert(sieve.factorize(72) == factors_72);

    std::vector<std::pair<int, int>> factors_90;
    factors_90.emplace_back(2, 1);
    factors_90.emplace_back(3, 2);
    factors_90.emplace_back(5, 1);
    assert(sieve.factorize(90) == factors_90);

    const std::vector<int> expected_divisors = {1, 2, 3, 4, 6, 12};
    assert(sieve.divisors(12) == expected_divisors);
    assert(sieve.totient(36) == 12);
    assert(sieve.mobius(30) == -1);
    assert(sieve.mobius(12) == 0);
    assert(sieve.totient_table()[36] == 12);
    assert(sieve.mobius_table()[30] == -1);
}

void test_large_factorization() {
    using m1une::math::divisors;
    using m1une::math::euler_phi;
    using m1une::math::is_prime;
    using m1une::math::mobius;
    using m1une::math::prime_factorize;

    assert(is_prime(2));
    assert(is_prime(18446744073709551557ULL));
    assert(!is_prime(341550071728321ULL));

    const uint64_t semiprime = 1000000007ULL * 1000000009ULL;
    const auto factors = prime_factorize(semiprime);
    assert(factors.size() == 2);
    assert((factors[0] == std::pair<uint64_t, int>(1000000007ULL, 1)));
    assert((factors[1] == std::pair<uint64_t, int>(1000000009ULL, 1)));

    const std::vector<uint64_t> expected_divisors = {1, 2, 3, 4, 6, 9, 12, 18, 36};
    assert(divisors(36) == expected_divisors);
    assert(euler_phi(36) == 12);
    assert(mobius(30) == -1);
    assert(mobius(12) == 0);

    m1une::math::PrimeSieve sieve(10000);
    for (int value = 1; value <= sieve.limit(); value++) {
        const auto small_factors = sieve.factorize(value);
        const auto large_factors = prime_factorize(value);
        assert(small_factors.size() == large_factors.size());
        for (int i = 0; i < int(small_factors.size()); i++) {
            assert(uint64_t(small_factors[i].first) == large_factors[i].first);
            assert(small_factors[i].second == large_factors[i].second);
        }
    }
}

void test_primitive_root() {
    using m1une::math::euler_phi;
    using m1une::math::has_primitive_root;
    using m1une::math::primitive_root;

    assert(primitive_root(2) == 1);
    assert(primitive_root(4) == 3);
    assert(primitive_root(18) == 5);
    assert(primitive_root(998244353) == 3);
    assert(primitive_root(1000000007) == 5);
    assert(!has_primitive_root(8));
    assert(!has_primitive_root(12));
    assert(primitive_root(8) == 0);

    for (uint64_t mod = 2; mod <= 200; mod++) {
        const uint64_t root = primitive_root(mod);
        const uint64_t phi = euler_phi(mod);
        if (root == 0) {
            assert(!has_primitive_root(mod));
            bool found = false;
            for (uint64_t candidate = 1; candidate < mod; candidate++) {
                if (std::gcd(candidate, mod) != 1) continue;
                uint64_t value = 1;
                uint64_t order = 0;
                do {
                    value = value * candidate % mod;
                    order++;
                } while (value != 1);
                if (order == phi) found = true;
            }
            assert(!found);
            continue;
        }

        assert(has_primitive_root(mod));
        assert(std::gcd(root, mod) == 1);

        uint64_t value = 1;
        for (uint64_t exponent = 1; exponent < phi; exponent++) {
            value = value * root % mod;
            assert(value != 1);
        }
        value = value * root % mod;
        assert(value == 1);

        for (uint64_t candidate = 1; candidate < root; candidate++) {
            if (std::gcd(candidate, mod) != 1) continue;
            value = 1;
            uint64_t order = 0;
            do {
                value = value * candidate % mod;
                order++;
            } while (value != 1);
            assert(order != phi);
        }
    }
}

void test_totient_sum() {
    using m1une::math::totient_sum;
    using m1une::math::TotientSum;

    TotientSum solver(100);
    assert(solver.precalculation_limit() == 100);
    assert(solver.prefix_sum(0) == 0);
    assert(solver.prefix_sum(1) == 1);
    assert(solver(10) == 32);
    assert(totient_sum(100, 10) == 3044);

    m1une::math::PrimeSieve sieve(20000);
    const std::vector<int> phi = sieve.totient_table();
    __uint128_t expected = 0;
    for (int value = 1; value <= 20000; value++) {
        expected += static_cast<uint64_t>(phi[value]);
        assert(solver.prefix_sum(value) == expected);
    }

    for (uint64_t n : std::vector<uint64_t>{1, 2, 10, 100, 1000, 10000}) {
        __uint128_t left = 0;
        for (uint64_t q = 1; q <= n;) {
            const uint64_t quotient = n / q;
            const uint64_t next = n / quotient + 1;
            left += static_cast<__uint128_t>(next - q) * solver.prefix_sum(quotient);
            q = next;
        }
        const __uint128_t wide_n = n;
        assert(left == wide_n * (wide_n + 1) / 2);
    }
}

void test_combinatorics() {
    using Mint = m1une::math::modint998244353;
    m1une::math::Combinatorics<Mint> combinations(100);

    assert(combinations.factorial(5) == Mint(120));
    assert(combinations.inverse(5) * Mint(5) == Mint(1));
    assert(combinations.binom(10, 3) == Mint(120));
    assert(combinations.binom(3, 5) == Mint(0));
    assert(combinations.perm(5, 3) == Mint(60));
    assert(combinations.multiset(3, 4) == Mint(15));
    assert(combinations.multiset(0, 0) == Mint(1));
    assert(combinations.catalan(5) == Mint(42));

    assert(combinations.binom(100, 0) == Mint(1));
    assert(combinations.binom(100, 100) == Mint(1));
}

void test_combinatorial_sequences() {
    using Mint = m1une::math::modint998244353;

    const std::vector<Mint> catalan = m1une::math::catalan_numbers<Mint>(10);
    const std::vector<int> expected_catalan =
        {1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796};
    for (int i = 0; i <= 10; i++) assert(catalan[i] == Mint(expected_catalan[i]));
    m1une::math::Combinatorics<Mint> catalan_combinations(100);
    const std::vector<Mint> more_catalan =
        m1une::math::catalan_numbers<Mint>(50);
    for (int i = 0; i <= 50; i++) {
        assert(more_catalan[i] == catalan_combinations.catalan(i));
    }

    const std::vector<Mint> bernoulli = m1une::math::bernoulli_numbers<Mint>(20);
    assert(bernoulli[0] == Mint(1));
    assert(bernoulli[1] * Mint(2) == Mint(-1));
    assert(bernoulli[2] * Mint(6) == Mint(1));
    assert(bernoulli[4] * Mint(30) == Mint(-1));
    assert(bernoulli[6] * Mint(42) == Mint(1));
    for (int i = 3; i <= 19; i += 2) assert(bernoulli[i] == Mint(0));

    m1une::math::Combinatorics<Mint> combinations(21);
    for (int n = 1; n <= 20; n++) {
        Mint sum = 0;
        for (int k = 0; k <= n; k++) {
            sum += combinations.binom(n + 1, k) * bernoulli[k];
        }
        assert(sum == Mint(0));
    }

    const std::vector<Mint> bell = m1une::math::bell_numbers<Mint>(10);
    const std::vector<int> expected_bell =
        {1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975};
    for (int i = 0; i <= 10; i++) assert(bell[i] == Mint(expected_bell[i]));

    const std::vector<Mint> stirling_zero =
        m1une::math::stirling_numbers_second_kind<Mint>(0);
    assert(stirling_zero == std::vector<Mint>{Mint(1)});
    const std::vector<Mint> stirling =
        m1une::math::stirling_numbers_second_kind<Mint>(5);
    const std::vector<int> expected_stirling = {0, 1, 15, 25, 10, 1};
    for (int i = 0; i <= 5; i++) {
        assert(stirling[i] == Mint(expected_stirling[i]));
    }
    std::vector<Mint> stirling_dp(1, Mint(1));
    const std::vector<Mint> more_bell = m1une::math::bell_numbers<Mint>(30);
    for (int n = 0; n <= 30; n++) {
        if (n > 0) {
            std::vector<Mint> next(n + 1);
            for (int k = 1; k <= n; k++) {
                next[k] = stirling_dp[k - 1];
                if (k < int(stirling_dp.size())) {
                    next[k] += Mint(k) * stirling_dp[k];
                }
            }
            stirling_dp = std::move(next);
        }
        const std::vector<Mint> row =
            m1une::math::stirling_numbers_second_kind<Mint>(n);
        assert(row == stirling_dp);
        Mint sum = 0;
        for (Mint value : row) sum += value;
        assert(sum == more_bell[n]);
    }

    const std::vector<Mint> partitions = m1une::math::partition_numbers<Mint>(100);
    const std::vector<int> expected_partitions =
        {1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42};
    for (int i = 0; i <= 10; i++) {
        assert(partitions[i] == Mint(expected_partitions[i]));
    }
    std::vector<Mint> partition_dp(101);
    partition_dp[0] = 1;
    for (int part = 1; part <= 100; part++) {
        for (int sum = part; sum <= 100; sum++) {
            partition_dp[sum] += partition_dp[sum - part];
        }
    }
    assert(partitions == partition_dp);

    const std::vector<Mint> derangements =
        m1une::math::derangement_numbers<Mint>(10);
    const std::vector<int> expected_derangements =
        {1, 0, 1, 2, 9, 44, 265, 1854, 14833, 133496, 1334961};
    for (int i = 0; i <= 10; i++) {
        assert(derangements[i] == Mint(expected_derangements[i]));
    }
    m1une::math::Combinatorics<Mint> derangement_combinations(30);
    const std::vector<Mint> more_derangements =
        m1une::math::derangement_numbers<Mint>(30);
    Mint alternating_sum = 1;
    for (int n = 0; n <= 30; n++) {
        if (n > 0) {
            const Mint term = derangement_combinations.inverse_factorial(n);
            alternating_sum += (n & 1) ? Mint(0) - term : term;
        }
        assert(
            more_derangements[n] ==
            derangement_combinations.factorial(n) * alternating_sum
        );
    }
}

int main() {
    m1une::utilities::FastInput fast_input;
    m1une::utilities::FastOutput fast_output;

    test_number_theory();
    test_prime_sieve();
    test_large_factorization();
    test_primitive_root();
    test_totient_sum();
    test_combinatorics();
    test_combinatorial_sequences();

    long long a, b;
    fast_input >> a >> b;
    fast_output << a + b << '\n';
}
#line 1 "verify/math/math_algorithms.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"

#include <algorithm>
#include <cassert>
#include <cstdint>
#line 1 "utilities/fast_io.hpp"



#line 5 "utilities/fast_io.hpp"
#include <array>
#include <cerrno>
#include <charconv>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#line 12 "utilities/fast_io.hpp"
#include <cstring>
#include <iterator>
#include <string>
#include <sys/stat.h>
#include <type_traits>
#include <utility>
#include <unistd.h>
#include <vector>

namespace m1une {
namespace utilities {

struct FastOutput;

namespace internal {

// Shared with the convenience helpers in template.hpp.
inline FastOutput* standard_output_instance = nullptr;

// Detect std::begin(x), std::end(x).
template <class T, class = void>
struct is_range : std::false_type {};

template <class T>
struct is_range<T, std::void_t<
    decltype(std::begin(std::declval<T&>())),
    decltype(std::end(std::declval<T&>()))
>> : std::true_type {};

template <class T>
inline constexpr bool is_range_v = is_range<T>::value;

template <class T>
using range_reference_t = decltype(*std::begin(std::declval<T&>()));

template <class T>
using range_value_t = std::remove_cv_t<std::remove_reference_t<range_reference_t<T>>>;

template <class T, class = void>
struct range_stored_value {
    using type = range_value_t<T>;
};

template <class T>
struct range_stored_value<T, std::void_t<typename std::remove_cv_t<std::remove_reference_t<T>>::value_type>> {
    using type = typename std::remove_cv_t<std::remove_reference_t<T>>::value_type;
};

template <class T>
using range_stored_value_t = typename range_stored_value<T>::type;

// Treat strings and C strings as scalar output objects, not as ranges.
template <class T>
struct is_char_array : std::false_type {};

template <class T, std::size_t N>
struct is_char_array<T[N]>
    : std::bool_constant<std::is_same_v<std::remove_cv_t<T>, char>> {};

template <class T>
struct is_string_like
    : std::bool_constant<
          std::is_same_v<std::decay_t<T>, std::string>
          || std::is_same_v<std::decay_t<T>, const char*>
          || std::is_same_v<std::decay_t<T>, char*>
          || is_char_array<std::remove_reference_t<T>>::value
      > {};

template <class T>
inline constexpr bool is_string_like_v = is_string_like<T>::value;

// ModInt-like type: x.val() is printable, and x can be assigned from long long.
template <class T, class = void>
struct has_val_method : std::false_type {};

template <class T>
struct has_val_method<T, std::void_t<decltype(std::declval<const T&>().val())>>
    : std::true_type {};

template <class T>
inline constexpr bool has_val_method_v = has_val_method<T>::value;

template <class T, class = void>
struct has_static_mod_raw : std::false_type {};

template <class T>
struct has_static_mod_raw<
    T, std::void_t<decltype(T::mod()), decltype(T::raw(std::declval<uint32_t>()))>>
    : std::true_type {};

template <class T>
inline constexpr bool has_static_mod_raw_v = has_static_mod_raw<T>::value;

// libstdc++ before GCC 16 does not classify __int128 as an integral type in
// strict ISO modes such as -std=c++23. Keep the fast-I/O interface independent
// of that implementation detail.
template <class T>
inline constexpr bool is_integral_v =
    std::is_integral_v<T>
    || std::is_same_v<std::remove_cv_t<T>, __int128_t>
    || std::is_same_v<std::remove_cv_t<T>, __uint128_t>;

template <class T>
inline constexpr bool is_signed_v =
    std::is_signed_v<T>
    || std::is_same_v<std::remove_cv_t<T>, __int128_t>;

template <class T>
struct make_unsigned {
    using type = std::make_unsigned_t<T>;
};

template <>
struct make_unsigned<__int128_t> {
    using type = __uint128_t;
};

template <>
struct make_unsigned<__uint128_t> {
    using type = __uint128_t;
};

template <class T>
using make_unsigned_t = typename make_unsigned<std::remove_cv_t<T>>::type;

}  // namespace internal

struct FastInput {
    static constexpr int buffer_size = 1 << 20;

   private:
    std::FILE* _stream;
    char _buffer[buffer_size];
    int _position;
    int _length;
    int _file_descriptor;
    bool _streaming;

    bool refill() {
        _position = 0;
        if (_streaming) {
            ssize_t length;
            do {
                length = ::read(_file_descriptor, _buffer, buffer_size);
            } while (length < 0 && errno == EINTR);
            if (length <= 0) {
                _length = 0;
                return false;
            }
            _length = int(length);
        } else {
            _length = int(std::fread(_buffer, 1, buffer_size, _stream));
        }
        return _length != 0;
    }

    template <class T>
    bool read_integer_from_stream(T& value) {
        if (!skip_spaces()) return false;
        int c = read_char_raw();

        bool negative = false;
        if (c == '-') {
            negative = true;
            c = read_char_raw();
        }

        if constexpr (internal::is_signed_v<T>) {
            T result = 0;
            while ('0' <= c && c <= '9') {
                result = negative ? result * 10 - (c - '0')
                                  : result * 10 + (c - '0');
                c = read_char_raw();
            }
            value = result;
        } else {
            T result = 0;
            while ('0' <= c && c <= '9') {
                result = result * 10 + T(c - '0');
                c = read_char_raw();
            }
            value = negative ? T(0) - result : result;
        }
        return true;
    }

    bool prepare_number() {
        if (_length - _position >= 64) return true;
        const int remaining = _length - _position;
        if (remaining > 0) std::memmove(_buffer, _buffer + _position, remaining);
        const int added = int(std::fread(_buffer + remaining, 1, buffer_size - remaining, _stream));
        _position = 0;
        _length = remaining + added;
        if (_length < buffer_size) _buffer[_length] = '\0';
        return _length != 0;
    }

   public:
    explicit FastInput(std::FILE* stream = stdin)
        : _stream(stream),
          _position(0),
          _length(0),
          _file_descriptor(::fileno(stream)),
          _streaming([&] {
              struct stat status;
              return _file_descriptor >= 0
                     && ::fstat(_file_descriptor, &status) == 0
                     && !S_ISREG(status.st_mode);
          }()) {}

    FastInput(const FastInput&) = delete;
    FastInput& operator=(const FastInput&) = delete;

    int read_char_raw() {
        if (_position == _length && !refill()) return EOF;
        return _buffer[_position++];
    }

    bool skip_spaces() {
        int c = read_char_raw();
        while (c != EOF && c <= ' ') c = read_char_raw();
        if (c == EOF) return false;
        --_position;
        return true;
    }

    bool read(char& value) {
        if (!skip_spaces()) return false;
        value = char(read_char_raw());
        return true;
    }

    bool read(std::string& value) {
        if (!skip_spaces()) return false;
        value.clear();
        while (true) {
            const int begin = _position;
            while (_position < _length &&
                   static_cast<unsigned char>(_buffer[_position]) > ' ') {
                ++_position;
            }
            value.append(_buffer + begin, _position - begin);
            if (_position < _length) {
                ++_position;
                return true;
            }
            if (!refill()) return true;
        }
    }

    bool read(bool& value) {
        int x;
        if (!read(x)) return false;
        value = x != 0;
        return true;
    }

    template <class T>
    std::enable_if_t<
        internal::is_integral_v<T>
            && !std::is_same_v<std::remove_cv_t<T>, bool>
            && !std::is_same_v<std::remove_cv_t<T>, char>,
        bool
    >
    read(T& value) {
        if (_streaming) return read_integer_from_stream(value);
        if (!prepare_number()) return false;
        int c = static_cast<unsigned char>(_buffer[_position++]);
        while (c <= ' ') c = static_cast<unsigned char>(_buffer[_position++]);

        bool negative = false;
        if (c == '-') {
            negative = true;
            c = static_cast<unsigned char>(_buffer[_position++]);
        }

        if constexpr (internal::is_signed_v<T>) {
            T result = 0;
            while ('0' <= c && c <= '9') {
                const int first = c - '0';
                const int second = static_cast<unsigned char>(_buffer[_position]) - '0';
                if (0 <= second && second <= 9) {
                    result = negative ? result * 100 - (first * 10 + second)
                                      : result * 100 + (first * 10 + second);
                    ++_position;
                } else {
                    result = negative ? result * 10 - first : result * 10 + first;
                }
                c = static_cast<unsigned char>(_buffer[_position++]);
            }
            value = result;
        } else {
            T result = 0;
            while ('0' <= c && c <= '9') {
                const unsigned first = unsigned(c - '0');
                const int second = static_cast<unsigned char>(_buffer[_position]) - '0';
                if (0 <= second && second <= 9) {
                    result = result * 100 + T(first * 10 + unsigned(second));
                    ++_position;
                } else {
                    result = result * 10 + T(first);
                }
                c = static_cast<unsigned char>(_buffer[_position++]);
            }
            value = negative ? T(0) - result : result;
        }
        if (_position > _length) _position = _length;
        return true;
    }

    template <class T>
    std::enable_if_t<std::is_floating_point_v<T>, bool>
    read(T& value) {
        if (!skip_spaces()) return false;
        int c = read_char_raw();
        bool negative = false;
        if (c == '-' || c == '+') {
            negative = c == '-';
            c = read_char_raw();
        }

        long double result = 0;
        while ('0' <= c && c <= '9') {
            result = result * 10 + (c - '0');
            c = read_char_raw();
        }
        if (c == '.') {
            long double place = 0.1L;
            c = read_char_raw();
            while ('0' <= c && c <= '9') {
                result += (c - '0') * place;
                place *= 0.1L;
                c = read_char_raw();
            }
        }
        if (c == 'e' || c == 'E') {
            c = read_char_raw();
            bool exponent_negative = false;
            if (c == '-' || c == '+') {
                exponent_negative = c == '-';
                c = read_char_raw();
            }
            int exponent = 0;
            while ('0' <= c && c <= '9') {
                exponent = exponent * 10 + (c - '0');
                c = read_char_raw();
            }
            long double scale = 1;
            long double power = 10;
            while (exponent > 0) {
                if (exponent & 1) scale *= power;
                power *= power;
                exponent >>= 1;
            }
            result = exponent_negative ? result / scale : result * scale;
        }
        value = static_cast<T>(negative ? -result : result);
        return true;
    }

    template <class T>
    std::enable_if_t<
        internal::has_val_method_v<T>
            && !internal::is_integral_v<T>
            && !internal::is_range_v<T>,
        bool
    >
    read(T& value) {
        long long x;
        if (!read(x)) return false;
        if constexpr (internal::has_static_mod_raw_v<T>) {
            if (x >= 0 && uint64_t(x) < uint64_t(T::mod())) {
                value = T::raw(uint32_t(x));
            } else {
                value = T(x);
            }
        } else {
            value = T(x);
        }
        return true;
    }

    template <class First, class Second>
    bool read(std::pair<First, Second>& value) {
        if (!read(value.first)) return false;
        return read(value.second);
    }

    template <class Range>
    std::enable_if_t<
        internal::is_range_v<Range>
            && !internal::is_string_like_v<Range>,
        bool
    >
    read(Range& range) {
        using StoredValue = internal::range_stored_value_t<Range>;
        constexpr bool nested = internal::is_range_v<StoredValue>
                                && !internal::is_string_like_v<StoredValue>;

        for (auto&& value : range) {
            if constexpr (std::is_same_v<StoredValue, bool> && !nested) {
                bool x;
                if (!read(x)) return false;
                value = x;
            } else {
                if (!read(value)) return false;
            }
        }
        return true;
    }

    template <class First, class Second, class... Rest>
    bool read(First& first, Second& second, Rest&... rest) {
        if (!read(first)) return false;
        return read(second, rest...);
    }

    template <class T>
    FastInput& operator>>(T& value) {
        if (!read(value)) std::abort();
        return *this;
    }
};

struct FastOutput {
    static constexpr int buffer_size = 1 << 20;

   private:
    inline static const auto digit_quads = [] {
        std::array<char, 40000> result{};
        for (int i = 0; i < 10000; i++) {
            int value = i;
            for (int j = 3; j >= 0; j--) {
                result[4 * i + j] = char('0' + value % 10);
                value /= 10;
            }
        }
        return result;
    }();

    std::FILE* _stream;
    char _buffer[buffer_size];
    int _position;
    int _precision;
    std::chars_format _float_format;
    char _range_separator;
    std::string* _capture = nullptr;

    template <class T>
    std::string format_cell(const T& value) {
        std::string result;
        struct CaptureGuard {
            std::string*& target;
            std::string* previous;
            ~CaptureGuard() { target = previous; }
        } guard{_capture, _capture};
        _capture = &result;
        write(value);
        return result;
    }

    template <class Matrix>
    void write_aligned_matrix(const Matrix& matrix) {
        std::vector<std::vector<std::string>> rows;
        std::vector<std::size_t> widths;
        for (const auto& row : matrix) {
            auto& cells = rows.emplace_back();
            std::size_t column = 0;
            for (const auto& value : row) {
                cells.push_back(format_cell(value));
                if (column == widths.size()) widths.push_back(0);
                widths[column] = std::max(widths[column], cells.back().size());
                ++column;
            }
        }
        bool first = true;
        for (const auto& row : rows) {
            if (!first) write_char('\n');
            first = false;
            for (std::size_t column = 0; column < row.size(); ++column) {
                if (column != 0) write_char(_range_separator);
                for (std::size_t padding = row[column].size();
                     padding < widths[column]; ++padding) {
                    write_char(' ');
                }
                write(row[column]);
            }
        }
    }

   public:
    explicit FastOutput(std::FILE* stream = stdout)
        : _stream(stream),
          _position(0),
          _precision(6),
          _float_format(std::chars_format::general),
          _range_separator(' ') {
        if (_stream == stdout
            && internal::standard_output_instance == nullptr) {
            internal::standard_output_instance = this;
        }
    }

    FastOutput(const FastOutput&) = delete;
    FastOutput& operator=(const FastOutput&) = delete;

    ~FastOutput() {
        flush();
        if (internal::standard_output_instance == this) {
            internal::standard_output_instance = nullptr;
        }
    }

    void flush() {
        if (_position != 0) {
            std::fwrite(_buffer, 1, _position, _stream);
            _position = 0;
        }
        std::fflush(_stream);
    }

    void write_char(char c) {
        if (_capture != nullptr) {
            _capture->push_back(c);
            return;
        }
        if (_position == buffer_size) flush();
        _buffer[_position++] = c;
    }

    void write(const char* s) {
        while (*s != '\0') write_char(*s++);
    }

    void write(const std::string& s) {
        if (_capture != nullptr) {
            _capture->append(s);
            return;
        }
        std::size_t position = 0;
        while (position < s.size()) {
            if (_position == buffer_size) flush();
            const std::size_t copied =
                std::min<std::size_t>(buffer_size - _position, s.size() - position);
            std::memcpy(_buffer + _position, s.data() + position, copied);
            _position += int(copied);
            position += copied;
        }
    }

    void write(char c) {
        write_char(c);
    }

    void write(bool value) {
        write_char(value ? '1' : '0');
    }

    template <class T>
    std::enable_if_t<std::is_floating_point_v<T>>
    write(T value) {
        char digits[128];
        auto [end, error] = std::to_chars(
            digits,
            digits + sizeof(digits),
            value,
            _float_format,
            _precision
        );
        if (error != std::errc()) std::abort();
        for (const char* pointer = digits; pointer != end; pointer++) {
            write_char(*pointer);
        }
    }

    template <class T>
    std::enable_if_t<
        internal::is_integral_v<T>
            && !std::is_same_v<std::remove_cv_t<T>, bool>
            && !std::is_same_v<std::remove_cv_t<T>, char>
    >
    write(T value) {
        using Raw = std::remove_cv_t<T>;
        using Unsigned = internal::make_unsigned_t<Raw>;

        Unsigned magnitude;
        if constexpr (internal::is_signed_v<Raw>) {
            if (value < 0) {
                write_char('-');
                magnitude = Unsigned(0) - Unsigned(value);
            } else {
                magnitude = Unsigned(value);
            }
        } else {
            magnitude = value;
        }

        if (magnitude == 0) {
            write_char('0');
            return;
        }

        unsigned chunks[16];
        int count = 0;
        while (magnitude >= 10000) {
            const Unsigned quotient = magnitude / 10000;
            chunks[count++] = unsigned(magnitude - quotient * 10000);
            magnitude = quotient;
        }
        if (_capture == nullptr && _position > buffer_size - 64) flush();
        char captured[64];
        char* const begin = _capture != nullptr ? captured : _buffer + _position;
        char* destination = begin;
        const unsigned leading = unsigned(magnitude);
        const char* first = digit_quads.data() + 4 * leading;
        int skip = leading < 10 ? 3 : leading < 100 ? 2 : leading < 1000 ? 1 : 0;
        for (; skip < 4; skip++) *destination++ = first[skip];
        while (count--) {
            const char* digits = digit_quads.data() + 4 * chunks[count];
            std::memcpy(destination, digits, 4);
            destination += 4;
        }
        if (_capture != nullptr) {
            _capture->append(begin, destination - begin);
        } else {
            _position += int(destination - begin);
        }
    }

    template <class T>
    std::enable_if_t<
        internal::has_val_method_v<T>
            && !internal::is_integral_v<T>
            && !internal::is_range_v<T>
    >
    write(const T& value) {
        write(value.val());
    }

    template <class First, class Second>
    void write(const std::pair<First, Second>& value) {
        write(value.first);
        write_char(' ');
        write(value.second);
    }

    template <class Range>
    std::enable_if_t<
        internal::is_range_v<Range>
            && !internal::is_string_like_v<Range>
    >
    write(const Range& range) {
        using StoredValue = internal::range_stored_value_t<const Range>;
        constexpr bool nested = internal::is_range_v<StoredValue>
                                && !internal::is_string_like_v<StoredValue>;

        bool first = true;
        for (const auto& value : range) {
            if (!first) write_char(nested ? '\n' : _range_separator);
            first = false;
            if constexpr (std::is_same_v<StoredValue, bool> && !nested) {
                write(static_cast<bool>(value));
            } else {
                write(value);
            }
        }
    }

    template <class First, class... Rest>
    void print(const First& first, const Rest&... rest) {
        write(first);
        ((write_char(' '), write(rest)), ...);
    }

    void println() {
        write_char('\n');
    }

    void set_precision(int precision) {
        _precision = precision;
    }

    void set_fixed(int precision = 6) {
        _float_format = std::chars_format::fixed;
        _precision = precision;
    }

    void set_general(int precision = 6) {
        _float_format = std::chars_format::general;
        _precision = precision;
    }

    void set_range_separator(char separator) {
        _range_separator = separator;
    }

    template <class Matrix>
    void write_aligned(const Matrix& matrix) {
        using Row = internal::range_stored_value_t<const Matrix>;
        using Cell = internal::range_stored_value_t<const Row>;
        static_assert(internal::is_range_v<Row> && !internal::is_string_like_v<Row>,
                      "write_aligned requires a two-dimensional range");
        static_assert(!internal::is_range_v<Cell> || internal::is_string_like_v<Cell>,
                      "write_aligned requires scalar cells");
        write_aligned_matrix(matrix);
    }

    template <class Matrix>
    void println_aligned(const Matrix& matrix) {
        write_aligned(matrix);
        write_char('\n');
    }

    template <class... Args>
    void println(const Args&... args) {
        print(args...);
        write_char('\n');
    }

    template <class T>
    FastOutput& operator<<(const T& value) {
        write(value);
        return *this;
    }
};

}  // namespace utilities
}  // namespace m1une


#line 7 "verify/math/math_algorithms.test.cpp"
#include <numeric>
#line 10 "verify/math/math_algorithms.test.cpp"

#line 1 "math/all.hpp"



#line 1 "math/base_n.hpp"



#line 6 "math/base_n.hpp"
#include <concepts>
#include <limits>
#include <optional>
#line 11 "math/base_n.hpp"

namespace m1une {
namespace math {

// Returns the canonical most-significant-first base-n digits of a
// nonnegative integer. Zero is represented by one zero digit.
template <std::integral Integer>
requires(!std::same_as<std::remove_cv_t<Integer>, bool>)
std::vector<int> to_base_n(Integer value, int base) {
    assert(2 <= base);
    if (base < 2) return {};
    if constexpr (std::signed_integral<Integer>) {
        assert(0 <= value);
        if (value < 0) return {};
    }

    using Unsigned = std::make_unsigned_t<Integer>;
    Unsigned remaining = static_cast<Unsigned>(value);
    if (remaining == 0) return {0};

    std::vector<int> digits;
    const unsigned long long unsigned_base = static_cast<unsigned int>(base);
    while (remaining != 0) {
        digits.push_back(int(remaining % unsigned_base));
        remaining = Unsigned(remaining / unsigned_base);
    }
    std::reverse(digits.begin(), digits.end());
    return digits;
}

// Converts most-significant-first base-n digits to an integer.
// Returns nullopt for an invalid digit or when the result does not fit.
template <std::integral Integer, class DigitSequence>
requires(!std::same_as<std::remove_cv_t<Integer>, bool>)
std::optional<Integer> checked_from_base_n(const DigitSequence& digits,
                                           int base) {
    assert(2 <= base);
    if (base < 2) return std::nullopt;

    using Unsigned = std::make_unsigned_t<Integer>;
    constexpr Unsigned integer_limit = [] {
        if constexpr (std::signed_integral<Integer>) {
            return Unsigned(std::numeric_limits<Integer>::max());
        } else {
            return std::numeric_limits<Integer>::max();
        }
    }();
    const unsigned __int128 limit = integer_limit;
    const unsigned __int128 unsigned_base = static_cast<unsigned int>(base);

    unsigned __int128 value = 0;
    for (const auto& digit_reference : digits) {
        using Digit = std::remove_cvref_t<decltype(digit_reference)>;
        static_assert(std::integral<Digit>);
        static_assert(!std::same_as<Digit, bool>);
        Digit digit = digit_reference;
        if constexpr (std::signed_integral<Digit>) {
            if (digit < 0) return std::nullopt;
        }
        using UnsignedDigit = std::make_unsigned_t<Digit>;
        UnsignedDigit unsigned_digit = static_cast<UnsignedDigit>(digit);
        unsigned __int128 converted_digit = unsigned_digit;
        if (converted_digit >= unsigned_base) {
            return std::nullopt;
        }

        if (converted_digit > limit ||
            value > (limit - converted_digit) / unsigned_base) {
            return std::nullopt;
        }
        value = value * unsigned_base + converted_digit;
    }
    return static_cast<Integer>(static_cast<Unsigned>(value));
}

// Converts most-significant-first base-n digits to an integer.
// Every digit must be valid and the result must fit in Integer.
template <std::integral Integer, class DigitSequence>
requires(!std::same_as<std::remove_cv_t<Integer>, bool>)
Integer from_base_n(const DigitSequence& digits, int base) {
    std::optional<Integer> result = checked_from_base_n<Integer>(digits, base);
    assert(result.has_value());
    return result.value_or(Integer(0));
}

}  // namespace math
}  // namespace m1une


#line 1 "math/bernoulli.hpp"



#line 7 "math/bernoulli.hpp"

#line 1 "math/fps/formal_power_series.hpp"



#line 10 "math/fps/formal_power_series.hpp"

#line 1 "math/modular_square_root.hpp"



#line 7 "math/modular_square_root.hpp"

namespace m1une {
namespace math {

namespace internal {

inline uint64_t modular_square_root_multiply(uint64_t lhs, uint64_t rhs, uint64_t mod) {
    return static_cast<uint64_t>(static_cast<unsigned __int128>(lhs) * rhs % mod);
}

inline uint64_t modular_square_root_power(uint64_t base, uint64_t exponent, uint64_t mod) {
    uint64_t result = 1 % mod;
    while (exponent > 0) {
        if (exponent & 1) result = modular_square_root_multiply(result, base, mod);
        base = modular_square_root_multiply(base, base, mod);
        exponent >>= 1;
    }
    return result;
}

}  // namespace internal

// Returns x such that x * x = value (mod prime), or nullopt when no such x exists.
// The modulus must be prime.
inline std::optional<uint64_t> modular_square_root(uint64_t value, uint64_t prime) {
    assert(prime >= 2);
    value %= prime;
    if (value == 0 || prime == 2) return value;

    if (internal::modular_square_root_power(value, (prime - 1) / 2, prime) != 1) {
        return std::nullopt;
    }
    if (prime % 4 == 3) {
        return internal::modular_square_root_power(value, prime / 4 + 1, prime);
    }

    uint64_t odd_part = prime - 1;
    int power_of_two = 0;
    while ((odd_part & 1) == 0) {
        odd_part >>= 1;
        power_of_two++;
    }

    uint64_t non_residue = 2;
    while (internal::modular_square_root_power(non_residue, (prime - 1) / 2, prime) == 1) {
        non_residue++;
    }

    uint64_t c = internal::modular_square_root_power(non_residue, odd_part, prime);
    uint64_t root = internal::modular_square_root_power(value, odd_part / 2 + 1, prime);
    uint64_t remainder = internal::modular_square_root_power(value, odd_part, prime);
    int remaining_power = power_of_two;

    while (remainder != 1) {
        int exponent = 1;
        uint64_t squared = internal::modular_square_root_multiply(remainder, remainder, prime);
        while (squared != 1) {
            squared = internal::modular_square_root_multiply(squared, squared, prime);
            exponent++;
        }

        uint64_t correction = c;
        for (int i = 0; i < remaining_power - exponent - 1; i++) {
            correction = internal::modular_square_root_multiply(correction, correction, prime);
        }
        root = internal::modular_square_root_multiply(root, correction, prime);
        c = internal::modular_square_root_multiply(correction, correction, prime);
        remainder = internal::modular_square_root_multiply(remainder, c, prime);
        remaining_power = exponent;
    }
    return root;
}

template <class Mint>
std::optional<Mint> modular_square_root(Mint value) {
    auto root = modular_square_root(static_cast<uint64_t>(value.val()),
                                    static_cast<uint64_t>(Mint::mod()));
    if (!root.has_value()) return std::nullopt;
    return Mint(*root);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/fps/convolution.hpp"



#line 9 "math/fps/convolution.hpp"
#include <new>
#line 13 "math/fps/convolution.hpp"

#if defined(__GNUC__) && !defined(__clang__) && \
    (defined(__x86_64__) || defined(__i386__)) && \
    !defined(M1UNE_FPS_DISABLE_X86_SIMD)
#include <immintrin.h>
#define M1UNE_FPS_HAS_X86_SIMD 1
#pragma GCC push_options
#pragma GCC target("avx2,bmi")
#endif

#line 1 "math/fps/internal/ntt998_faster.hpp"



#ifdef M1UNE_FPS_HAS_X86_SIMD

#line 9 "math/fps/internal/ntt998_faster.hpp"

#include <immintrin.h>

namespace m1une {
namespace fps {
namespace internal {
namespace fast998_v2 {

// Fixed-modulus AVX2 transform with an in-register degree-8 residue product.

using u32=unsigned;
using u64=unsigned long long;
using idt=std::size_t;
using I256=__m256i;
inline void store256(void*p,I256 x){
    _mm256_store_si256((I256*)p,x);
}
inline I256 load256(const void*p){
    return _mm256_load_si256((const I256*)p);
}
constexpr u32 shrk(u32 x,u32 M){
    return std::min(x,x-M);
}
constexpr u32 dilt(u32 x,u32 M){
    return std::min(x,x+M);
}
constexpr u32 reduce(u64 x,u32 niv,u32 M){
    return (x+u64(u32(x)*niv)*M)>>32;
}
constexpr u32 mul(u32 x,u32 y,u32 niv,u32 M){
    return reduce(u64(x)*y,niv,M);
}
constexpr u32 mul_s(u32 x,u32 y,u32 niv,u32 M){
    return shrk(reduce(u64(x)*y,niv,M),M);
}
constexpr u32 qpw(u32 a,u32 b,u32 niv,u32 M,u32 r){
    for(;b;b>>=1,a=mul(a,a,niv,M)){
        if(b&1){
            r=mul(r,a,niv,M);
        }
    }
    return r;
}
constexpr u32 qpw_s(u32 a,u32 b,u32 niv,u32 M,u32 r){
    return shrk(qpw(a,b,niv,M,r),M);
}
inline I256 shrk32(I256 x,I256 M){
    return _mm256_min_epu32(x,_mm256_sub_epi32(x,M));
}
inline I256 dilt32(I256 x,I256 M){
    return _mm256_min_epu32(x,_mm256_add_epi32(x,M));
}
inline I256 Ladd32(I256 x,I256 y,I256){
    return _mm256_add_epi32(x,y);
}
inline I256 Lsub32(I256 x,I256 y,I256 M){
    return _mm256_add_epi32(_mm256_sub_epi32(x,y),M);
}
inline I256 add32(I256 x,I256 y,I256 M){
    return shrk32(_mm256_add_epi32(x,y),M);
}
inline I256 sub32(I256 x,I256 y,I256 M){
    return dilt32(_mm256_sub_epi32(x,y),M);
}
template<int msk>inline I256 neg32_m(I256 x,I256 M){
    return _mm256_blend_epi32(x,_mm256_sub_epi32(M,x),msk);
}
inline I256 reduce(I256 a,I256 b,I256 niv,I256 M){
    I256 c=_mm256_mul_epu32(a,niv),d=_mm256_mul_epu32(b,niv);
    c=_mm256_mul_epu32(c,M),d=_mm256_mul_epu32(d,M);
    return _mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(a,c),32),_mm256_add_epi64(b,d),0xaa);
}
inline I256 mul(I256 a,I256 b,I256 niv,I256 M){
    return reduce(_mm256_mul_epu32(a,b),_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(b,32)),niv,M);
}
inline I256 mul_s(I256 a,I256 b,I256 niv,I256 M){
    return shrk32(mul(a,b,niv,M),M);
}
inline I256 mul_bsm(I256 a,I256 b,I256 niv,I256 M){
    return reduce(_mm256_mul_epu32(a,b),_mm256_mul_epu32(_mm256_srli_epi64(a,32),b),niv,M);
}
inline I256 mul_bsmfxd(I256 a,I256 b,I256 bniv,I256 M){
    I256 cc=_mm256_mul_epu32(a,bniv),dd=_mm256_mul_epu32(_mm256_srli_epi64(a,32),bniv);
    I256 c=_mm256_mul_epu32(a,b),d=_mm256_mul_epu32(_mm256_srli_epi64(a,32),b);
    cc=_mm256_mul_epu32(cc,M),dd=_mm256_mul_epu32(dd,M);
    return _mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),_mm256_add_epi64(d,dd),0xaa);
}
inline I256 mul_bfxd(I256 a,I256 b,I256 bniv,I256 M){
    I256 cc=_mm256_mul_epu32(a,bniv),dd=_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(bniv,32));
    I256 c=_mm256_mul_epu32(a,b),d=_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(b,32));
    cc=_mm256_mul_epu32(cc,M),dd=_mm256_mul_epu32(dd,M);
    return _mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),_mm256_add_epi64(d,dd),0xaa);
}
inline I256 mul_upd_rt(I256 a,I256 bu,I256 M){
    I256 cc=_mm256_mul_epu32(a,bu),c=_mm256_mul_epu32(a,_mm256_srli_epi64(bu,32));
    cc=_mm256_mul_epu32(cc,M);
    return shrk32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),M);
}
constexpr auto _mxlg=26,_lg_itth=6;
constexpr auto _itth=idt(1)<<_lg_itth;
static_assert(_lg_itth%2==0);
struct FNTT32_info{
    u32 mod,mod2,niv,one,r2,r3,img,imgniv,RT1[_mxlg];
    alignas(32) std::array<u32,8> rt3[_mxlg-2],rt3i[_mxlg-2],bwbr,bwb,bwbi,rt4[_mxlg-3],rt4niv[_mxlg-3],rt4i[_mxlg-3],rt4iniv[_mxlg-3],pr2,pr4,pr2niv,pr4niv,pr2i,pr2iniv,pr4i,pr4iniv;
    constexpr FNTT32_info(const u32 m):mod(m),mod2(m*2),niv([&]{u32 n=2+m;for(int i=0;i<4;++i){n*=2+m*n;}return n;}()),one((-m)%m),r2((-u64(m))%m),r3(mul_s(r2,r2,niv,m)),img{},imgniv{},RT1{},rt3{},rt3i{},bwbr{},bwb{},bwbi{},rt4{},rt4niv{},rt4i{},rt4iniv{},pr2{},pr4{},pr2niv{},pr4niv{},pr2i{},pr2iniv{},pr4i{},pr4iniv{}{
        const int k=__builtin_ctz(m-1);
		u32 _g=mul(3,r2,niv,mod);
        for(;;++_g){
            if(qpw_s(_g,mod>>1,niv,mod,one)!=one){
                break;
            }
        }
		_g=qpw(_g,mod>>k,niv,mod,one);
        u32 rt1[_mxlg-1],rt1i[_mxlg-1];
        rt1[k-2]=_g,rt1i[k-2]=qpw(_g,mod-2,niv,mod,one);
        for(int i=k-2;i>0;--i){
            rt1[i-1]=mul(rt1[i],rt1[i],niv,mod);
            rt1i[i-1]=mul(rt1i[i],rt1i[i],niv,mod);
        }
        RT1[k-1]=qpw_s(_g,3,niv,mod,one);
        for(int i=k-1;i>0;--i){
			RT1[i-1]=mul_s(RT1[i],RT1[i],niv,mod);
        }
        img=rt1[0],imgniv=img*niv;
        bwbr={one,0,one,0,one};
        bwb={rt1[1],0,rt1[0],0,mod-mul_s(rt1[0],rt1[1],niv,mod)};
        bwbi={rt1i[1],0,rt1i[0],0,mul_s(rt1i[0],rt1i[1],niv,mod)};
        u32 pr=one,pri=one;
        for(int i=0;i<k-2;++i){
            const u32 r=mul_s(pr,rt1[i+1],niv,mod),ri=mul_s(pri,rt1i[i+1],niv,mod);
            const u32 r2=mul_s(r,r,niv,mod),r2i=mul_s(ri,ri,niv,mod);
            const u32 r3=mul_s(r,r2,niv,mod),r3i=mul_s(ri,r2i,niv,mod);
            rt3[i]={r*niv,r,r2*niv,r2,r3*niv,r3};
            rt3i[i]={ri*niv,ri,r2i*niv,r2i,r3i*niv,r3i};
            pr=mul(pr,rt1i[i+1],niv,mod),pri=mul(pri,rt1[i+1],niv,mod);
        }
        pr=one,pri=one;
        for(int i=0;i<k-3;++i){
            const u32 r=mul_s(pr,rt1[i+2],niv,mod),ri=mul_s(pri,rt1i[i+2],niv,mod);
            rt4[i][0]=rt4i[i][0]=one;
            for(int j=1;j<8;++j){
                rt4[i][j]=mul_s(rt4[i][j-1],r,niv,mod);
                rt4i[i][j]=mul_s(rt4i[i][j-1],ri,niv,mod);
            }
            for(int j=0;j<8;++j){
                rt4niv[i][j]=rt4[i][j]*niv;
                rt4iniv[i][j]=rt4i[i][j]*niv;
            }
            pr=mul(pr,rt1i[i+2],niv,mod),pri=mul(pri,rt1[i+2],niv,mod);
        }
        pr2={one,one,one,img,one,one,one,img};
        pr4={one,one,one,one,one,rt1[1],img,mul_s(img,rt1[1],niv,mod)};
        const u32 nr2=mod-r2,imgr2=mul_s(img,r2,niv,mod);
        pr2i={nr2,nr2,nr2,imgr2,nr2,nr2,nr2,imgr2};
        pr4i={one,one,one,one,one,rt1i[1],rt1i[0],mul_s(rt1i[0],rt1i[1],niv,mod)};
        for(int j=0;j<8;++j){
            pr2niv[j]=pr2[j]*niv,pr4niv[j]=pr4[j]*niv;
            pr2iniv[j]=pr2i[j]*niv,pr4iniv[j]=pr4i[j]*niv;
        }
    }
};
inline void vector_dif(I256*const f,const idt n,const FNTT32_info*info){
    alignas(32) std::array<u32,8> st_1[_mxlg>>1];
    const I256 Mod=_mm256_set1_epi32(info->mod),Mod2=_mm256_set1_epi32(info->mod2),Niv=_mm256_set1_epi32(info->niv);
    const I256 Img=_mm256_set1_epi32(info->img),ImgNiv=_mm256_set1_epi32(info->imgniv),id=_mm256_setr_epi32(0,2,0,4,0,2,0,4);
    const int lgn=__builtin_ctzll(n);
    std::fill(st_1,st_1+(lgn>>1),info->bwb);
    const idt nn=n>>(lgn&1),m=std::min(n,_itth),mm=std::min(nn,_itth);
    // I256 rr=_mm256_set1_epi32(info->one);
    if(nn!=n){
        for(idt i=0;i<nn;++i){
            auto const p0=f+i,p1=f+nn+i;
            const auto f0=load256(p0),f1=load256(p1);
            const auto g0=add32(f0,f1,Mod2),g1=Lsub32(f0,f1,Mod2);
            store256(p0,g0),store256(p1,g1);
        }
    }
    for(idt L=nn>>2;L>0;L>>=2){
        for(idt i=0;i<L;++i){
            auto const p0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;
            const auto f1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);
            const auto g3=mul_bsmfxd(Lsub32(f1,f3,Mod2),Img,ImgNiv,Mod),g1=add32(f1,f3,Mod2);
            const auto g0=add32(f0,f2,Mod2),g2=sub32(f0,f2,Mod2);
            const auto h0=add32(g0,g1,Mod2),h1=Lsub32(g0,g1,Mod2);
            const auto h2=Ladd32(g2,g3,Mod2),h3=Lsub32(g2,g3,Mod2);
            store256(p0,h0),store256(p1,h1),store256(p2,h2),store256(p3,h3);
        }
    }
    for(idt j=0;j<n;j+=m){
        int t=((j==0)?std::min(_lg_itth,lgn):__builtin_ctzll(j))&-2,p=(t-2)>>1;
        for(idt L=(idt(1)<<t)>>2;L>=_itth;L>>=2,t-=2,--p){
            auto rt=load256(st_1+p);
            const auto r1=_mm256_permutevar8x32_epi32(rt,id);
            const auto r1Niv=_mm256_permutevar8x32_epi32(_mm256_mul_epu32(rt,Niv),id);
            rt=mul_upd_rt(rt,load256(info->rt3+__builtin_ctzll(~j>>t)),Mod);
            const auto r2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB),nr3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);
            const auto r2Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_BBBB),nr3Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_DDDD);
            store256(st_1+p,rt);
            for(idt i=0;i<L;++i){
                auto const p0=f+i+j,p1=p0+L,p2=p1+L,p3=p2+L;
                const auto f1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);
                const auto g1=mul_bsmfxd(f1,r1,r1Niv,Mod),ng3=mul_bsmfxd(f3,nr3,nr3Niv,Mod);
                const auto g2=mul_bsmfxd(f2,r2,r2Niv,Mod),g0=shrk32(f0,Mod2);
                const auto h3=mul_bsmfxd(Ladd32(g1,ng3,Mod2),Img,ImgNiv,Mod),h1=sub32(g1,ng3,Mod2);
                const auto h0=add32(g0,g2,Mod2),h2=sub32(g0,g2,Mod2);
                const auto u0=Ladd32(h0,h1,Mod2),u1=Lsub32(h0,h1,Mod2);
                const auto u2=Ladd32(h2,h3,Mod2),u3=Lsub32(h2,h3,Mod2);
                store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);
            }
        }
        I256*const g=f+j;
        for(idt l=mm,L=mm>>2;L;l=L,L>>=2,t-=2,--p){
            auto rt=load256(st_1+p);
            for(idt i=(j==0?l:0),k=(j+i)>>t;i<m;i+=l,++k){
                const auto r1=_mm256_permutevar8x32_epi32(rt,id);
                const auto r2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB);
                const auto nr3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);
                for(idt j=0;j<L;++j){
                    auto const p0=g+i+j,p1=p0+L,p2=p1+L,p3=p2+L;
                    const auto f1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);
                    const auto g1=mul_bsm(f1,r1,Niv,Mod),ng3=mul_bsm(f3,nr3,Niv,Mod);
                    const auto g2=mul_bsm(f2,r2,Niv,Mod),g0=shrk32(f0,Mod2);
                    const auto h3=mul_bsmfxd(Ladd32(g1,ng3,Mod2),Img,ImgNiv,Mod),h1=sub32(g1,ng3,Mod2);
                    const auto h0=add32(g0,g2,Mod2),h2=sub32(g0,g2,Mod2);
                    const auto u0=Ladd32(h0,h1,Mod2),u1=Lsub32(h0,h1,Mod2);
                    const auto u2=Ladd32(h2,h3,Mod2),u3=Lsub32(h2,h3,Mod2);
                    store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);
                }
                rt=mul_upd_rt(rt,load256(info->rt3+__builtin_ctzll(~k)),Mod);
            }
            store256(st_1+p,rt);
        }
        // const auto pr2=load256(&info->pr2),pr4=load256(&info->pr4);
        // const auto pr2Niv=load256(&info->pr2niv),pr4Niv=load256(&info->pr4niv);
        // for(idt i=j;i<j+m;++i){
        //     auto fi=load256(f+i);
        //     fi=mul(fi,rr,Niv,Mod);
        //     rr=shrk32(mul_bfxd(rr,load256(info->rt4+__builtin_ctzll(~i)),load256(info->rt4niv+__builtin_ctzll(~i)),Mod),Mod);
        //     fi=mul_bfxd(Ladd32(neg32_m<0xf0>(fi,Mod2),_mm256_permute2x128_si256(fi,fi,1),Mod2),pr4,pr4Niv,Mod);
        //     fi=mul_bfxd(Ladd32(neg32_m<0xcc>(fi,Mod2),_mm256_shuffle_epi32(fi,0x4e),Mod2),pr2,pr2Niv,Mod);
        //     fi=sub32(_mm256_shuffle_epi32(fi,0xb1),neg32_m<0x55>(fi,Mod2),Mod2);
        //     store256(f+i,fi);
        // }
    }
}
template<bool shrk=false>inline void vector_dit(I256*const f,idt n,const FNTT32_info*const info){
    alignas(32) std::array<u32,8> st_1[_mxlg>>1];
    const I256 Mod=_mm256_set1_epi32(info->mod),Mod2=_mm256_set1_epi32(info->mod2),Niv=_mm256_set1_epi32(info->niv);
    const I256 Img=_mm256_set1_epi32(info->img),ImgNiv=_mm256_set1_epi32(info->imgniv),id=_mm256_setr_epi32(0,2,0,4,0,2,0,4);
    const int lgn=__builtin_ctzll(n);
    std::fill(st_1,st_1+(_lg_itth>>1),info->bwbr);
    std::fill(st_1+(_lg_itth>>1),st_1+(_mxlg>>1),info->bwbi);
    const idt nn=n>>(lgn&1),mm=std::min(nn,_itth);
    // I256 rr=_mm256_set1_epi32((info->mod-1)>>(lgn+3));
    for(idt j=0;j<n;j+=mm){
        // const auto pr2=load256(&info->pr2i),pr4=load256(&info->pr4i);
        // const auto pr2Niv=load256(&info->pr2iniv),pr4Niv=load256(&info->pr4iniv);
        // for(idt i=j;i<j+mm;++i){
        //     auto fi=load256(f+i);
        //     const auto rt=rr;
        //     rr=shrk32(mul_bfxd(rr,load256(info->rt4i+__builtin_ctzll(~i)),load256(info->rt4iniv+__builtin_ctzll(~i)),Mod),Mod);
        //     fi=mul_bfxd(Ladd32(neg32_m<0xaa>(fi,Mod2),_mm256_shuffle_epi32(fi,0xb1),Mod2),pr2,pr2Niv,Mod);
        //     fi=mul_bfxd(Ladd32(neg32_m<0xcc>(fi,Mod2),_mm256_shuffle_epi32(fi,0x4e),Mod2),pr4,pr4Niv,Mod);
        //     fi=mul(Ladd32(neg32_m<0xf0>(fi,Mod2),_mm256_permute2x128_si256(fi,fi,1),Mod2),rt,Niv,Mod);
        //     store256(f+i,fi);
        // }
        I256*const g=f+j;
        int t=2,p=0;
        for(idt l=4,L=1;l<=mm;L=l,l<<=2,t+=2,++p){
            auto rt=load256(st_1+p);
            for(idt i=0,k=j>>t;i<mm;i+=l,++k){
                const auto r1=_mm256_permutevar8x32_epi32(rt,id);
                const auto r2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB);
                const auto r3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);
                for(idt j=0;j<L;++j){
                    auto const p0=g+i+j,p1=p0+L,p2=p1+L,p3=p2+L;
                    const auto f0=load256(p0),f1=load256(p1),f2=load256(p2),f3=load256(p3);
                    const auto g0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);
                    const auto g2=add32(f2,f3,Mod2),g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod);
                    const auto h0=Ladd32(g0,g2,Mod2),h1=Ladd32(g1,g3,Mod2);
                    const auto h2=Lsub32(g0,g2,Mod2),h3=Lsub32(g1,g3,Mod2);
                    const auto u0=shrk32(h0,Mod2),u1=mul_bsm(h1,r1,Niv,Mod);
                    const auto u2=mul_bsm(h2,r2,Niv,Mod),u3=mul_bsm(h3,r3,Niv,Mod);
                    store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);
                }
                rt=mul_upd_rt(rt,load256(info->rt3i+__builtin_ctzll(~k)),Mod);
            }
            store256(st_1+p,rt);
        }
        int tt=std::min(__builtin_ctzll(~(j>>_lg_itth))+_lg_itth,lgn);
        for(idt L=_itth,l=L<<2;t<=tt;L=l,l<<=2,t+=2,++p){
            if((j+_itth)==l){
                if(shrk && l==n){
                    for(idt i=0;i<L;++i){
                        auto const p0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;
                        const auto f2=load256(p2),f3=load256(p3),f0=load256(p0),f1=load256(p1);
                        const auto g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod),g2=add32(f2,f3,Mod2);
                        const auto g0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);
                        const auto h0=add32(g0,g2,Mod2),h1=add32(g1,g3,Mod2);
                        const auto h2=sub32(g0,g2,Mod2),h3=sub32(g1,g3,Mod2);
                        const auto u0=shrk32(h0,Mod),u1=shrk32(h1,Mod);
                        const auto u2=shrk32(h2,Mod),u3=shrk32(h3,Mod);
                        store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);
                    }
                }
                else{
                    for(idt i=0;i<L;++i){
                        auto const p0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;
                        const auto f2=load256(p2),f3=load256(p3),f0=load256(p0),f1=load256(p1);
                        const auto g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod),g2=add32(f2,f3,Mod2);
                        const auto g0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);
                        const auto h0=add32(g0,g2,Mod2),h1=add32(g1,g3,Mod2);
                        const auto h2=sub32(g0,g2,Mod2),h3=sub32(g1,g3,Mod2);
                        store256(p0,h0),store256(p1,h1),store256(p2,h2),store256(p3,h3);
                    }
                }
            }
            else{
                auto rt=load256(st_1+p);
                const auto r1=_mm256_permutevar8x32_epi32(rt,id);
                const auto r1Niv=_mm256_permutevar8x32_epi32(_mm256_mul_epu32(rt,Niv),id);
                rt=mul_upd_rt(rt,load256(info->rt3i+__builtin_ctzll(~j>>t)),Mod);
                const auto r2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB),r3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);
                const auto r2Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_BBBB),r3Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_DDDD);
                store256(st_1+p,rt);
                for(idt i=0;i<L;++i){
                    auto const p0=f+j+_itth-l+i,p1=p0+L,p2=p1+L,p3=p2+L;
                    const auto f0=load256(p0),f1=load256(p1),f2=load256(p2),f3=load256(p3);
                    const auto g0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);
                    const auto g2=add32(f2,f3,Mod2),g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod);
                    const auto h0=Ladd32(g0,g2,Mod2),h1=Ladd32(g1,g3,Mod2);
                    const auto h2=Lsub32(g0,g2,Mod2),h3=Lsub32(g1,g3,Mod2);
                    const auto u0=shrk32(h0,Mod2),u1=mul_bsmfxd(h1,r1,r1Niv,Mod);
                    const auto u2=mul_bsmfxd(h2,r2,r2Niv,Mod),u3=mul_bsmfxd(h3,r3,r3Niv,Mod);
                    store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);
                }
            }
        }
    }
    if(shrk && nn==n && n<=_itth){
        for(idt i=0;i<n;++i){
            const auto f0=load256(f+i);
            store256(f+i,shrk32(f0,Mod));
        }
    }
    if(nn!=n){
        for(idt i=0;i<nn;++i){
            auto const p0=f+i,p1=f+nn+i;
            const auto f0=load256(p0),f1=load256(p1);
            const auto g0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);
            if constexpr(shrk){
                const auto h0=shrk32(g0,Mod),h1=shrk32(g1,Mod);
                store256(p0,h0),store256(p1,h1);
            }
            else{
                store256(p0,g0),store256(p1,g1);
            }
        }
    }
}
// Returns fx * f[0,8) * g[0,8) (mod x^8 - ww).
[[gnu::always_inline]] inline I256 convolve8(const I256*f,const I256*g,I256 ww,I256 fx,I256 Niv,I256 Mod,I256 Mod2){
    const auto raa=load256(f),rbb=load256(g);
    const auto taa=shrk32(raa,Mod2),bb=shrk32(mul_bsm(rbb,fx,Niv,Mod),Mod);
    const auto aw=shrk32(mul_bsm(taa,ww,Niv,Mod),Mod);
    const auto aa=shrk32(taa,Mod);
    const auto awa=_mm256_permute2x128_si256(aa,aw,3);
    
    const auto b0=_mm256_permute4x64_epi64(bb,0x00),b1=_mm256_shuffle_epi32(b0,_MM_PERM_CDAB);
    const auto a0=aa,a1=_mm256_srli_epi64(a0,32);
    const auto aw7=_mm256_alignr_epi8(aa,awa,12);
    auto res00=_mm256_mul_epu32(a0,b0);
    auto res01=_mm256_mul_epu32(a1,b0);
    auto res10=_mm256_mul_epu32(aw7,b1);
    auto res11=_mm256_mul_epu32(a0,b1);

    const auto b2=_mm256_permute4x64_epi64(bb,0x55),b3=_mm256_shuffle_epi32(b2,_MM_PERM_CDAB);
    const auto aw6=_mm256_alignr_epi8(aa,awa,8);
    const auto aw5=_mm256_alignr_epi8(aa,awa,4);
    res00=_mm256_add_epi64(res00,_mm256_mul_epu32(aw6,b2));
    res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw7,b2));
    res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw5,b3));
    res11=_mm256_add_epi64(res11,_mm256_mul_epu32(aw6,b3));

    const auto b4=_mm256_permute4x64_epi64(bb,0xaa),b5=_mm256_shuffle_epi32(b4,_MM_PERM_CDAB);
    const auto aw3=_mm256_alignr_epi8(awa,aw,12);
    res00=_mm256_add_epi64(res00,_mm256_mul_epu32(awa,b4));
    res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw5,b4));
    res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw3,b5));
    res11=_mm256_add_epi64(res11,_mm256_mul_epu32(awa,b5));

    const auto b6=_mm256_permute4x64_epi64(bb,0xff),b7=_mm256_shuffle_epi32(b6,_MM_PERM_CDAB);
    const auto aw2=_mm256_alignr_epi8(awa,aw,8);
    const auto aw1=_mm256_alignr_epi8(awa,aw,4);
    res00=_mm256_add_epi64(res00,_mm256_mul_epu32(aw2,b6));
    res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw3,b6));
    res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw1,b7));
    res11=_mm256_add_epi64(res11,_mm256_mul_epu32(aw2,b7));

    res00=_mm256_add_epi64(res00,res10);
    res01=_mm256_add_epi64(res01,res11);

    return shrk32(reduce(res00,res01,Niv,Mod),Mod2);
}
inline void vector_convolution_direct(I256*f,const I256*g,idt lm,const FNTT32_info*const info){
    u32 RR=info->one;
    const auto mod=info->mod,niv=info->niv;
    const auto Fx=_mm256_set1_epi32(mul_s((mod-((mod-1)>>(__builtin_ctzll(lm)))),info->r3,niv,mod));
    const auto Niv=_mm256_set1_epi32(niv),Mod=_mm256_set1_epi32(mod),Mod2=_mm256_set1_epi32(info->mod2);
    for(idt i=0;i<lm;++i){
        store256(f+i,convolve8(f+i,g+i,_mm256_set1_epi32(RR),Fx,Niv,Mod,Mod2));
        RR=mul(RR,info->RT1[__builtin_ctzll(~i)],niv,mod);
    }
}
inline void vector_convolution_accumulate(I256*const result,const I256*const f,
                                          const I256*const g,idt lm,
                                          const FNTT32_info*const info){
    u32 RR=info->one;
    const auto mod=info->mod,niv=info->niv;
    const auto Fx=_mm256_set1_epi32(mul_s((mod-((mod-1)>>(__builtin_ctzll(lm)))),info->r3,niv,mod));
    const auto Niv=_mm256_set1_epi32(niv),Mod=_mm256_set1_epi32(mod),Mod2=_mm256_set1_epi32(info->mod2);
    for(idt i=0;i<lm;++i){
        const auto product=convolve8(f+i,g+i,_mm256_set1_epi32(RR),Fx,Niv,Mod,Mod2);
        store256(result+i,add32(load256(result+i),product,Mod2));
        RR=mul(RR,info->RT1[__builtin_ctzll(~i)],niv,mod);
    }
}

}  // namespace fast998_v2
}  // namespace internal
}  // namespace fps
}  // namespace m1une

#endif  // M1UNE_FPS_HAS_X86_SIMD


#line 24 "math/fps/convolution.hpp"
#ifdef M1UNE_FPS_HAS_X86_SIMD
#pragma GCC pop_options
#endif

#line 1 "math/modint.hpp"



#line 6 "math/modint.hpp"
#include <iostream>
#line 9 "math/modint.hpp"

namespace m1une {
namespace math {

template <uint32_t Modulus>
struct ModInt {
    static_assert(0 < Modulus, "Modulus must be positive");

   private:
    uint32_t _v;

   public:
    static constexpr uint32_t mod() {
        return Modulus;
    }

    static constexpr ModInt raw(uint32_t v) noexcept {
        ModInt x;
        x._v = v;
        return x;
    }

    constexpr ModInt() noexcept : _v(0) {}

    template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
    constexpr ModInt(Integer v) noexcept {
        if constexpr (std::is_signed_v<Integer>) {
            int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(Modulus);
            if (x < 0) x += Modulus;
            _v = static_cast<uint32_t>(x);
        } else {
            _v = static_cast<uint32_t>(static_cast<uint64_t>(v) % Modulus);
        }
    }

    constexpr uint32_t val() const noexcept {
        return _v;
    }

    constexpr ModInt& operator++() noexcept {
        _v++;
        if (_v == Modulus) _v = 0;
        return *this;
    }

    constexpr ModInt& operator--() noexcept {
        if (_v == 0) _v = Modulus;
        _v--;
        return *this;
    }

    constexpr ModInt operator++(int) noexcept {
        ModInt res = *this;
        ++*this;
        return res;
    }

    constexpr ModInt operator--(int) noexcept {
        ModInt res = *this;
        --*this;
        return res;
    }

    constexpr ModInt& operator+=(const ModInt& rhs) noexcept {
        _v += rhs._v;
        if (_v >= Modulus) _v -= Modulus;
        return *this;
    }

    constexpr ModInt& operator-=(const ModInt& rhs) noexcept {
        _v -= rhs._v;
        if (_v >= Modulus) _v += Modulus;
        return *this;
    }

    constexpr ModInt& operator*=(const ModInt& rhs) noexcept {
        uint64_t z = _v;
        z *= rhs._v;
        _v = static_cast<uint32_t>(z % Modulus);
        return *this;
    }

    constexpr ModInt& operator/=(const ModInt& rhs) noexcept {
        return *this *= rhs.inv();
    }

    constexpr ModInt operator+(const ModInt& rhs) const noexcept {
        return ModInt(*this) += rhs;
    }
    constexpr ModInt operator-(const ModInt& rhs) const noexcept {
        return ModInt(*this) -= rhs;
    }
    constexpr ModInt operator*(const ModInt& rhs) const noexcept {
        return ModInt(*this) *= rhs;
    }
    constexpr ModInt operator/(const ModInt& rhs) const noexcept {
        return ModInt(*this) /= rhs;
    }

    constexpr bool operator==(const ModInt& rhs) const noexcept {
        return _v == rhs._v;
    }
    constexpr bool operator!=(const ModInt& rhs) const noexcept {
        return _v != rhs._v;
    }

    constexpr ModInt pow(long long n) const noexcept {
        ModInt res = raw(1 % Modulus);
        ModInt x = n < 0 ? inv() : *this;
        uint64_t exponent = n < 0 ? uint64_t(-(n + 1)) + 1 : uint64_t(n);
        while (exponent > 0) {
            if (exponent & 1) res *= x;
            x *= x;
            exponent >>= 1;
        }
        return res;
    }

    constexpr ModInt inv() const noexcept {
        int64_t a = _v, b = Modulus, u = 1, v = 0;
        while (b) {
            int64_t t = a / b;
            a -= t * b;
            std::swap(a, b);
            u -= t * v;
            std::swap(u, v);
        }
        assert(a == 1);
        u %= Modulus;
        if (u < 0) u += Modulus;
        return raw(static_cast<uint32_t>(u));
    }

    friend std::ostream& operator<<(std::ostream& os, const ModInt& rhs) {
        return os << rhs._v;
    }

    friend std::istream& operator>>(std::istream& is, ModInt& rhs) {
        long long v;
        is >> v;
        rhs = ModInt(v);
        return is;
    }
};

using modint998244353 = ModInt<998244353>;
using modint1000000007 = ModInt<1000000007>;

template <int Id = 0>
struct DynamicModInt {
   private:
    uint32_t _v;
    inline static uint32_t _mod = 1;

   public:
    static uint32_t mod() noexcept {
        return _mod;
    }

    static void set_mod(uint32_t modulus) noexcept {
        assert(modulus > 0);
        assert(modulus <= uint32_t(1) << 31);
        _mod = modulus;
    }

    static DynamicModInt raw(uint32_t v) noexcept {
        assert(v < _mod);
        DynamicModInt x;
        x._v = v;
        return x;
    }

    DynamicModInt() noexcept : _v(0) {}

    template <class Integer, std::enable_if_t<std::is_integral_v<Integer>, int> = 0>
    DynamicModInt(Integer v) noexcept {
        if constexpr (std::is_signed_v<Integer>) {
            int64_t x = static_cast<int64_t>(v) % static_cast<int64_t>(_mod);
            if (x < 0) x += _mod;
            _v = static_cast<uint32_t>(x);
        } else {
            _v = static_cast<uint32_t>(static_cast<uint64_t>(v) % _mod);
        }
    }

    uint32_t val() const noexcept {
        return _v;
    }

    DynamicModInt& operator++() noexcept {
        _v++;
        if (_v == _mod) _v = 0;
        return *this;
    }

    DynamicModInt& operator--() noexcept {
        if (_v == 0) _v = _mod;
        _v--;
        return *this;
    }

    DynamicModInt operator++(int) noexcept {
        DynamicModInt result = *this;
        ++*this;
        return result;
    }

    DynamicModInt operator--(int) noexcept {
        DynamicModInt result = *this;
        --*this;
        return result;
    }

    DynamicModInt& operator+=(const DynamicModInt& rhs) noexcept {
        _v += rhs._v;
        if (_v >= _mod) _v -= _mod;
        return *this;
    }

    DynamicModInt& operator-=(const DynamicModInt& rhs) noexcept {
        _v -= rhs._v;
        if (_v >= _mod) _v += _mod;
        return *this;
    }

    DynamicModInt& operator*=(const DynamicModInt& rhs) noexcept {
        _v = static_cast<uint32_t>(uint64_t(_v) * rhs._v % _mod);
        return *this;
    }

    DynamicModInt& operator/=(const DynamicModInt& rhs) noexcept {
        return *this *= rhs.inv();
    }

    DynamicModInt operator+(const DynamicModInt& rhs) const noexcept {
        return DynamicModInt(*this) += rhs;
    }

    DynamicModInt operator-(const DynamicModInt& rhs) const noexcept {
        return DynamicModInt(*this) -= rhs;
    }

    DynamicModInt operator*(const DynamicModInt& rhs) const noexcept {
        return DynamicModInt(*this) *= rhs;
    }

    DynamicModInt operator/(const DynamicModInt& rhs) const noexcept {
        return DynamicModInt(*this) /= rhs;
    }

    bool operator==(const DynamicModInt& rhs) const noexcept {
        return _v == rhs._v;
    }

    bool operator!=(const DynamicModInt& rhs) const noexcept {
        return _v != rhs._v;
    }

    DynamicModInt pow(long long exponent) const noexcept {
        DynamicModInt result = raw(1 % _mod);
        DynamicModInt base = exponent < 0 ? inv() : *this;
        uint64_t magnitude =
            exponent < 0 ? uint64_t(-(exponent + 1)) + 1 : uint64_t(exponent);
        while (magnitude > 0) {
            if (magnitude & 1) result *= base;
            base *= base;
            magnitude >>= 1;
        }
        return result;
    }

    DynamicModInt inv() const noexcept {
        int64_t a = _v, b = _mod, u = 1, v = 0;
        while (b) {
            int64_t quotient = a / b;
            a -= quotient * b;
            std::swap(a, b);
            u -= quotient * v;
            std::swap(u, v);
        }
        assert(a == 1);
        u %= _mod;
        if (u < 0) u += _mod;
        return raw(static_cast<uint32_t>(u));
    }

    friend std::ostream& operator<<(std::ostream& os, const DynamicModInt& rhs) {
        return os << rhs._v;
    }

    friend std::istream& operator>>(std::istream& is, DynamicModInt& rhs) {
        long long value;
        is >> value;
        rhs = DynamicModInt(value);
        return is;
    }
};

}  // namespace math
}  // namespace m1une


#line 29 "math/fps/convolution.hpp"

namespace m1une {
namespace fps {

namespace internal {

template <class Mint, class = void>
struct has_static_modulus : std::false_type {};

template <class Mint>
struct has_static_modulus<
    Mint, std::void_t<decltype(std::integral_constant<uint32_t, Mint::mod()>{})>>
    : std::true_type {};

constexpr uint32_t primitive_root_constexpr(uint32_t mod) {
    if (mod == 2) return 1;
    if (mod == 167772161) return 3;
    if (mod == 469762049) return 3;
    if (mod == 754974721) return 11;
    if (mod == 998244353) return 3;
    if (mod == 1224736769) return 3;

    uint32_t divisors[32] = {};
    int count = 0;
    uint32_t x = mod - 1;
    for (uint32_t p = 2; uint64_t(p) * p <= x; p++) {
        if (x % p != 0) continue;
        divisors[count++] = p;
        while (x % p == 0) x /= p;
    }
    if (x > 1) divisors[count++] = x;

    for (uint32_t g = 2;; g++) {
        bool ok = true;
        for (int i = 0; i < count; i++) {
            uint64_t value = 1;
            uint64_t base = g;
            uint32_t exponent = (mod - 1) / divisors[i];
            while (exponent > 0) {
                if (exponent & 1) value = value * base % mod;
                base = base * base % mod;
                exponent >>= 1;
            }
            if (value == 1) {
                ok = false;
                break;
            }
        }
        if (ok) return g;
    }
}

constexpr int two_adic_order(uint32_t x) {
    int result = 0;
    while ((x & 1) == 0) {
        x >>= 1;
        result++;
    }
    return result;
}

template <class Mint>
struct NttRoots {
    static constexpr int max_base = two_adic_order(Mint::mod() - 1);
    std::array<Mint, max_base + 1> root;
    std::array<Mint, max_base + 1> inverse_root;
    std::array<Mint, max_base> rate;
    std::array<Mint, max_base> inverse_rate;
    std::array<Mint, max_base> rate_radix4;
    std::array<Mint, max_base> inverse_rate_radix4;

    NttRoots() {
        constexpr uint32_t primitive_root = primitive_root_constexpr(Mint::mod());
        for (int level = 1; level <= max_base; level++) {
            root[level] = Mint(primitive_root).pow((Mint::mod() - 1) >> level);
            inverse_root[level] = root[level].inv();
        }
        Mint product = 1;
        Mint inverse_product = 1;
        for (int i = 0; i + 1 < max_base; i++) {
            rate[i] = root[i + 2] * product;
            inverse_rate[i] = inverse_root[i + 2] * inverse_product;
            product *= inverse_root[i + 2];
            inverse_product *= root[i + 2];
        }
        product = 1;
        inverse_product = 1;
        for (int i = 0; i + 2 < max_base; i++) {
            rate_radix4[i] = root[i + 3] * product;
            inverse_rate_radix4[i] = inverse_root[i + 3] * inverse_product;
            product *= inverse_root[i + 3];
            inverse_product *= root[i + 3];
        }
    }
};

template <class Mint>
const NttRoots<Mint>& ntt_roots() {
    static const NttRoots<Mint> roots;
    return roots;
}

template <class Mint>
void ntt(std::vector<Mint>& a, bool inverse, bool normalize = true) {
    const int n = int(a.size());
    assert(n > 0 && (n & (n - 1)) == 0);
    assert((Mint::mod() - 1) % uint32_t(n) == 0);

    const auto& roots = ntt_roots<Mint>();
    const int height = two_adic_order(uint32_t(n));
    if (!inverse) {
        int phase = 0;
        while (phase < height) {
            if (height - phase == 1) {
                const int width = 1 << (height - phase - 1);
                Mint twiddle = 1;
                for (int block = 0; block < (1 << phase); block++) {
                    const int offset = block << (height - phase);
                    for (int i = 0; i < width; i++) {
                        const Mint left = a[offset + i];
                        const Mint right = a[offset + i + width] * twiddle;
                        a[offset + i] = left + right;
                        a[offset + i + width] = left - right;
                    }
                    if (block + 1 != (1 << phase))
                        twiddle *= roots.rate[__builtin_ctz(~uint32_t(block))];
                }
                phase++;
                continue;
            }

            const int width = 1 << (height - phase - 2);
            Mint twiddle = 1;
            const Mint imaginary = roots.root[2];
            for (int block = 0; block < (1 << phase); block++) {
                const Mint twiddle2 = twiddle * twiddle;
                const Mint twiddle3 = twiddle2 * twiddle;
                const int offset = block << (height - phase);
                for (int i = 0; i < width; i++) {
                    const uint64_t mod2 = uint64_t(Mint::mod()) * Mint::mod();
                    const uint64_t a0 = a[offset + i].val();
                    const uint64_t a1 = uint64_t(a[offset + i + width].val()) * twiddle.val();
                    const uint64_t a2 =
                        uint64_t(a[offset + i + 2 * width].val()) * twiddle2.val();
                    const uint64_t a3 =
                        uint64_t(a[offset + i + 3 * width].val()) * twiddle3.val();
                    const uint64_t a1na3i =
                        uint64_t(Mint(a1 + mod2 - a3).val()) * imaginary.val();
                    const uint64_t negative_a2 = mod2 - a2;
                    a[offset + i] = Mint(a0 + a2 + a1 + a3);
                    a[offset + i + width] = Mint(a0 + a2 + 2 * mod2 - a1 - a3);
                    a[offset + i + 2 * width] = Mint(a0 + negative_a2 + a1na3i);
                    a[offset + i + 3 * width] = Mint(a0 + negative_a2 + mod2 - a1na3i);
                }
                if (block + 1 != (1 << phase))
                    twiddle *= roots.rate_radix4[__builtin_ctz(~uint32_t(block))];
            }
            phase += 2;
        }
    } else {
        int phase = height;
        while (phase > 0) {
            if (phase == 1) {
                const int width = 1 << (height - phase);
                Mint twiddle = 1;
                for (int block = 0; block < (1 << (phase - 1)); block++) {
                    const int offset = block << (height - phase + 1);
                    for (int i = 0; i < width; i++) {
                        const Mint left = a[offset + i];
                        const Mint right = a[offset + i + width];
                        a[offset + i] = left + right;
                        a[offset + i + width] = (left - right) * twiddle;
                    }
                    if (block + 1 != (1 << (phase - 1)))
                        twiddle *= roots.inverse_rate[__builtin_ctz(~uint32_t(block))];
                }
                phase--;
                continue;
            }

            const int width = 1 << (height - phase);
            Mint twiddle = 1;
            const Mint inverse_imaginary = roots.inverse_root[2];
            for (int block = 0; block < (1 << (phase - 2)); block++) {
                const Mint twiddle2 = twiddle * twiddle;
                const Mint twiddle3 = twiddle2 * twiddle;
                const int offset = block << (height - phase + 2);
                for (int i = 0; i < width; i++) {
                    const uint64_t a0 = a[offset + i].val();
                    const uint64_t a1 = a[offset + i + width].val();
                    const uint64_t a2 = a[offset + i + 2 * width].val();
                    const uint64_t a3 = a[offset + i + 3 * width].val();
                    const uint64_t a2na3i =
                        uint64_t(Mint((Mint::mod() + a2 - a3) * inverse_imaginary.val()).val());
                    a[offset + i] = Mint(a0 + a1 + a2 + a3);
                    a[offset + i + width] =
                        Mint((a0 + Mint::mod() - a1 + a2na3i) * twiddle.val());
                    a[offset + i + 2 * width] = Mint(
                        (a0 + a1 + 2ULL * Mint::mod() - a2 - a3) * twiddle2.val());
                    a[offset + i + 3 * width] = Mint(
                        (a0 + Mint::mod() - a1 + Mint::mod() - a2na3i) * twiddle3.val());
                }
                if (block + 1 != (1 << (phase - 2)))
                    twiddle *= roots.inverse_rate_radix4[__builtin_ctz(~uint32_t(block))];
            }
            phase -= 2;
        }
        if (normalize) {
            const Mint inverse_n = Mint(n).inv();
            for (Mint& value : a) value *= inverse_n;
        }
    }
}

#ifdef M1UNE_FPS_HAS_X86_SIMD

#pragma GCC push_options
#pragma GCC target("avx2,bmi")

template <class Mint>
__attribute__((target("avx2,bmi"), hot))
std::vector<Mint> convolution_998244353_simd(const std::vector<Mint>& a,
                                             const std::vector<Mint>& b) {
    const int result_size = int(a.size() + b.size() - 1);
    int n = 1;
    while (n < result_size) n <<= 1;
    const bool squaring = &a == &b;
    auto* transformed_a = static_cast<uint32_t*>(
        ::operator new[](sizeof(uint32_t) * n, std::align_val_t(32)));
    auto* transformed_b = squaring
                              ? transformed_a
                              : static_cast<uint32_t*>(::operator new[](
                                    sizeof(uint32_t) * n, std::align_val_t(32)));
    if constexpr (std::is_same_v<Mint, math::ModInt<998244353>>) {
        static_assert(sizeof(Mint) == sizeof(uint32_t) && std::is_trivially_copyable_v<Mint>);
        std::memcpy(transformed_a, a.data(), sizeof(uint32_t) * a.size());
        if (!squaring)
            std::memcpy(transformed_b, b.data(), sizeof(uint32_t) * b.size());
    } else {
        for (int i = 0; i < int(a.size()); i++) transformed_a[i] = a[i].val();
        if (!squaring)
            for (int i = 0; i < int(b.size()); i++) transformed_b[i] = b[i].val();
    }
    std::memset(transformed_a + a.size(), 0, sizeof(uint32_t) * (n - a.size()));
    if (!squaring)
        std::memset(transformed_b + b.size(), 0, sizeof(uint32_t) * (n - b.size()));

    static constexpr fast998_v2::FNTT32_info transform(998244353);
    const std::size_t vector_size = std::size_t(n) >> 3;
    fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed_a), vector_size, &transform);
    if (!squaring)
        fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed_b), vector_size,
                              &transform);
    fast998_v2::vector_convolution_direct(
        reinterpret_cast<__m256i*>(transformed_a),
        reinterpret_cast<const __m256i*>(transformed_b), vector_size, &transform);
    fast998_v2::vector_dit<true>(reinterpret_cast<__m256i*>(transformed_a), vector_size,
                                 &transform);

    std::vector<Mint> result(result_size);
    for (int j = 0; j < result_size; j++) result[j] = Mint::raw(transformed_a[j]);
    ::operator delete[](transformed_a, std::align_val_t(32));
    if (!squaring) ::operator delete[](transformed_b, std::align_val_t(32));
    return result;
}

#pragma GCC pop_options

#endif

}  // namespace internal

template <class Mint>
std::vector<Mint> convolution_naive(const std::vector<Mint>& a, const std::vector<Mint>& b) {
    if (a.empty() || b.empty()) return {};
    std::vector<Mint> result(a.size() + b.size() - 1);
    if (a.size() < b.size()) {
        for (int i = 0; i < int(a.size()); i++) {
            for (int j = 0; j < int(b.size()); j++) result[i + j] += a[i] * b[j];
        }
    } else {
        for (int j = 0; j < int(b.size()); j++) {
            for (int i = 0; i < int(a.size()); i++) result[i + j] += a[i] * b[j];
        }
    }
    return result;
}

template <class Mint>
std::vector<Mint> convolution_ntt(const std::vector<Mint>& a, const std::vector<Mint>& b) {
    const int result_size = int(a.size() + b.size() - 1);
    int n = 1;
    while (n < result_size) n <<= 1;
    assert((Mint::mod() - 1) % uint32_t(n) == 0);

#ifdef M1UNE_FPS_HAS_X86_SIMD
    if constexpr (Mint::mod() == 998244353) {
        if (n >= 64 && __builtin_cpu_supports("avx2"))
            return internal::convolution_998244353_simd(a, b);
    }
#endif

    // Allocate the padded buffers directly.  Constructing from the inputs and
    // then resizing used to allocate and copy both large operands twice.
    const bool squaring = &a == &b;
    std::vector<Mint> fa(n);
    std::copy(a.begin(), a.end(), fa.begin());
    internal::ntt(fa, false);
    const Mint inverse_n = Mint(n).inv();
    if (squaring) {
        for (int i = 0; i < n; i++) fa[i] *= fa[i] * inverse_n;
    } else {
        std::vector<Mint> fb(n);
        std::copy(b.begin(), b.end(), fb.begin());
        internal::ntt(fb, false);
        for (int i = 0; i < n; i++) fa[i] *= fb[i] * inverse_n;
    }
    internal::ntt(fa, true, false);
    fa.resize(result_size);
    return fa;
}

namespace internal {

template <class Mint>
std::vector<Mint> convolution_998244353_blocked_scalar(const std::vector<Mint>& a,
                                                       const std::vector<Mint>& b,
                                                       int transform_size) {
    assert(Mint::mod() == 998244353);
    assert(transform_size >= 2 && (transform_size & (transform_size - 1)) == 0);
    assert((Mint::mod() - 1) % uint32_t(transform_size) == 0);

    const int block_size = transform_size / 2;
    const int a_blocks = int((a.size() + block_size - 1) / block_size);
    const int b_blocks = int((b.size() + block_size - 1) / block_size);

    auto transform_blocks = [&](const std::vector<Mint>& values, int block_count) {
        std::vector<std::vector<Mint>> blocks;
        blocks.reserve(block_count);
        for (int block = 0; block < block_count; block++) {
            const int begin = block * block_size;
            const int count = std::min(block_size, int(values.size()) - begin);
            std::vector<Mint> transformed(transform_size);
            std::copy_n(values.begin() + begin, count, transformed.begin());
            ntt(transformed, false);
            blocks.emplace_back(std::move(transformed));
        }
        return blocks;
    };

    std::vector<std::vector<Mint>> transformed_a = transform_blocks(a, a_blocks);
    std::vector<std::vector<Mint>> transformed_b = transform_blocks(b, b_blocks);
    const int result_size = int(a.size() + b.size() - 1);
    std::vector<Mint> result(result_size);
    std::vector<Mint> transformed_result(transform_size);
    for (int diagonal = 0; diagonal < a_blocks + b_blocks - 1; diagonal++) {
        std::fill(transformed_result.begin(), transformed_result.end(), Mint(0));
        const int first_a = std::max(0, diagonal - (b_blocks - 1));
        const int last_a = std::min(a_blocks - 1, diagonal);
        for (int a_block = first_a; a_block <= last_a; a_block++) {
            const int b_block = diagonal - a_block;
            for (int i = 0; i < transform_size; i++)
                transformed_result[i] +=
                    transformed_a[a_block][i] * transformed_b[b_block][i];
        }
        ntt(transformed_result, true);

        const int output_offset = diagonal * block_size;
        const int output_count = std::min(transform_size, result_size - output_offset);
        for (int i = 0; i < output_count; i++)
            result[output_offset + i] += transformed_result[i];
    }
    return result;
}

#ifdef M1UNE_FPS_HAS_X86_SIMD

class AlignedUint32Buffer {
   private:
    uint32_t* data_;

   public:
    explicit AlignedUint32Buffer(std::size_t size)
        : data_(static_cast<uint32_t*>(
              ::operator new[](sizeof(uint32_t) * size, std::align_val_t(32)))) {}

    AlignedUint32Buffer(const AlignedUint32Buffer&) = delete;
    AlignedUint32Buffer& operator=(const AlignedUint32Buffer&) = delete;

    AlignedUint32Buffer(AlignedUint32Buffer&& other) noexcept : data_(other.data_) {
        other.data_ = nullptr;
    }

    AlignedUint32Buffer& operator=(AlignedUint32Buffer&& other) noexcept {
        if (this == &other) return *this;
        ::operator delete[](data_, std::align_val_t(32));
        data_ = other.data_;
        other.data_ = nullptr;
        return *this;
    }

    ~AlignedUint32Buffer() {
        ::operator delete[](data_, std::align_val_t(32));
    }

    uint32_t* data() {
        return data_;
    }

    const uint32_t* data() const {
        return data_;
    }
};

template <class Mint>
__attribute__((target("avx2,bmi"), hot))
std::vector<Mint> convolution_998244353_blocked_simd(const std::vector<Mint>& a,
                                                     const std::vector<Mint>& b,
                                                     int transform_size) {
    assert(Mint::mod() == 998244353);
    assert(transform_size >= 64 && (transform_size & (transform_size - 1)) == 0);
    assert((Mint::mod() - 1) % uint32_t(transform_size) == 0);

    const int block_size = transform_size / 2;
    const int a_blocks = int((a.size() + block_size - 1) / block_size);
    const int b_blocks = int((b.size() + block_size - 1) / block_size);
    static constexpr fast998_v2::FNTT32_info transform(998244353);
    const std::size_t vector_size = std::size_t(transform_size) / 8;

    auto transform_blocks = [&](const std::vector<Mint>& values, int block_count) {
        std::vector<AlignedUint32Buffer> blocks;
        blocks.reserve(block_count);
        for (int block = 0; block < block_count; block++) {
            const int begin = block * block_size;
            const int count = std::min(block_size, int(values.size()) - begin);
            AlignedUint32Buffer transformed(transform_size);
            if constexpr (std::is_same_v<Mint, math::ModInt<998244353>>) {
                static_assert(sizeof(Mint) == sizeof(uint32_t) &&
                              std::is_trivially_copyable_v<Mint>);
                std::memcpy(transformed.data(), values.data() + begin,
                            sizeof(uint32_t) * count);
            } else {
                for (int i = 0; i < count; i++)
                    transformed.data()[i] = values[begin + i].val();
            }
            std::memset(transformed.data() + count, 0,
                        sizeof(uint32_t) * (transform_size - count));
            fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed.data()),
                                   vector_size, &transform);
            blocks.emplace_back(std::move(transformed));
        }
        return blocks;
    };

    std::vector<AlignedUint32Buffer> transformed_a = transform_blocks(a, a_blocks);
    std::vector<AlignedUint32Buffer> transformed_b = transform_blocks(b, b_blocks);
    const int result_size = int(a.size() + b.size() - 1);
    std::vector<Mint> result(result_size);
    AlignedUint32Buffer transformed_result(transform_size);
    for (int diagonal = 0; diagonal < a_blocks + b_blocks - 1; diagonal++) {
        std::memset(transformed_result.data(), 0, sizeof(uint32_t) * transform_size);
        const int first_a = std::max(0, diagonal - (b_blocks - 1));
        const int last_a = std::min(a_blocks - 1, diagonal);
        for (int a_block = first_a; a_block <= last_a; a_block++) {
            const int b_block = diagonal - a_block;
            fast998_v2::vector_convolution_accumulate(
                reinterpret_cast<__m256i*>(transformed_result.data()),
                reinterpret_cast<const __m256i*>(transformed_a[a_block].data()),
                reinterpret_cast<const __m256i*>(transformed_b[b_block].data()),
                vector_size, &transform);
        }
        fast998_v2::vector_dit<true>(
            reinterpret_cast<__m256i*>(transformed_result.data()), vector_size,
            &transform);

        const int output_offset = diagonal * block_size;
        const int output_count = std::min(transform_size, result_size - output_offset);
        for (int i = 0; i < output_count; i++) {
            uint32_t value = result[output_offset + i].val() + transformed_result.data()[i];
            if (value >= Mint::mod()) value -= Mint::mod();
            result[output_offset + i] = Mint::raw(value);
        }
    }
    return result;
}

#endif

template <class Mint>
std::vector<Mint> convolution_998244353_blocked(const std::vector<Mint>& a,
                                                const std::vector<Mint>& b,
                                                int transform_size = 1 << 23) {
#ifdef M1UNE_FPS_HAS_X86_SIMD
    if (transform_size >= 64 && __builtin_cpu_supports("avx2"))
        return convolution_998244353_blocked_simd(a, b, transform_size);
#endif
    return convolution_998244353_blocked_scalar(a, b, transform_size);
}

}  // namespace internal

template <class Mint>
std::vector<Mint> convolution(const std::vector<Mint>& a, const std::vector<Mint>& b) {
    if (a.empty() || b.empty()) return {};
    if (std::min(a.size(), b.size()) <= 32) return convolution_naive(a, b);

    const int result_size = int(a.size() + b.size() - 1);
    int n = 1;
    while (n < result_size) n <<= 1;
    if constexpr (internal::has_static_modulus<Mint>::value) {
        if constexpr (Mint::mod() == 998244353) {
            if (n > (1 << 23))
                return internal::convolution_998244353_blocked(a, b);
        }
        if ((Mint::mod() - 1) % uint32_t(n) == 0) return convolution_ntt(a, b);
    }

    using Mint1 = math::ModInt<167772161>;
    using Mint2 = math::ModInt<469762049>;
    using Mint3 = math::ModInt<754974721>;
    assert(n <= (1 << 24));

    [[maybe_unused]] const unsigned __int128 coefficient_bound =
        static_cast<unsigned __int128>(std::min(a.size(), b.size())) * (Mint::mod() - 1) *
        (Mint::mod() - 1);
    [[maybe_unused]] const unsigned __int128 crt_modulus =
        static_cast<unsigned __int128>(Mint1::mod()) * Mint2::mod() * Mint3::mod();
    assert(coefficient_bound < crt_modulus);

    auto converted_convolution = [&]<class OtherMint>() {
        std::vector<OtherMint> converted_a(a.size());
        std::vector<OtherMint> converted_b(b.size());
        for (int i = 0; i < int(a.size()); i++) converted_a[i] = OtherMint(a[i].val());
        for (int i = 0; i < int(b.size()); i++) converted_b[i] = OtherMint(b[i].val());
        return convolution_ntt(converted_a, converted_b);
    };
    std::vector<Mint1> c1 = converted_convolution.template operator()<Mint1>();
    std::vector<Mint2> c2 = converted_convolution.template operator()<Mint2>();
    std::vector<Mint3> c3 = converted_convolution.template operator()<Mint3>();
    static const uint64_t inverse_mod1_mod2 = Mint2(Mint1::mod()).inv().val();
    static const uint64_t mod1_mod3 = Mint1::mod() % Mint3::mod();
    static const uint64_t mod1_mod2_mod3 =
        mod1_mod3 * (Mint2::mod() % Mint3::mod()) % Mint3::mod();
    static const uint64_t inverse_mod1_mod2_mod3 = Mint3(uint32_t(mod1_mod2_mod3)).inv().val();

    const uint64_t target_mod = Mint::mod();
    const uint64_t mod1_target = Mint1::mod() % target_mod;
    const uint64_t mod1_mod2_target = mod1_target * (Mint2::mod() % target_mod) % target_mod;
    std::vector<Mint> result(result_size);
    for (int i = 0; i < result_size; i++) {
        const uint64_t r1 = c1[i].val();
        const uint64_t r2 = c2[i].val();
        const uint64_t r3 = c3[i].val();
        const uint64_t first =
            (r2 + Mint2::mod() - r1 % Mint2::mod()) % Mint2::mod() * inverse_mod1_mod2 %
            Mint2::mod();
        const uint64_t combined_mod3 =
            (r1 % Mint3::mod() + mod1_mod3 * (first % Mint3::mod())) % Mint3::mod();
        const uint64_t second =
            (r3 + Mint3::mod() - combined_mod3) % Mint3::mod() * inverse_mod1_mod2_mod3 %
            Mint3::mod();

        uint64_t value = r1 % target_mod;
        value = (value + mod1_target * (first % target_mod)) % target_mod;
        value = (value + mod1_mod2_target * (second % target_mod)) % target_mod;
        result[i] = Mint::raw(uint32_t(value));
    }
    return result;
}

}  // namespace fps
}  // namespace m1une

#ifdef M1UNE_FPS_HAS_X86_SIMD
#undef M1UNE_FPS_HAS_X86_SIMD
#endif


#line 13 "math/fps/formal_power_series.hpp"

namespace m1une {
namespace fps {

template <class Mint>
struct FormalPowerSeries : std::vector<Mint> {
    using std::vector<Mint>::vector;
    using Fps = FormalPowerSeries;

    FormalPowerSeries() = default;
    FormalPowerSeries(const std::vector<Mint>& values) : std::vector<Mint>(values) {}
    FormalPowerSeries(std::vector<Mint>&& values) : std::vector<Mint>(std::move(values)) {}

    Fps& shrink() {
        while (!this->empty() && this->back() == Mint(0)) this->pop_back();
        return *this;
    }

    Fps pre(int degree) const {
        assert(degree >= 0);
        Fps result(this->begin(), this->begin() + std::min<int>(degree, this->size()));
        result.resize(degree);
        return result;
    }

    Fps reversed(int size = -1) const {
        Fps result = *this;
        if (size >= 0) result.resize(size);
        std::reverse(result.begin(), result.end());
        return result;
    }

    Fps& operator+=(const Fps& rhs) {
        if (this->size() < rhs.size()) this->resize(rhs.size());
        for (int i = 0; i < int(rhs.size()); i++) (*this)[i] += rhs[i];
        return *this;
    }

    Fps& operator-=(const Fps& rhs) {
        if (this->size() < rhs.size()) this->resize(rhs.size());
        for (int i = 0; i < int(rhs.size()); i++) (*this)[i] -= rhs[i];
        return *this;
    }

    Fps& operator*=(const Fps& rhs) {
        std::vector<Mint> lhs(this->begin(), this->end());
        *this = convolution(lhs, rhs);
        return *this;
    }

    Fps& operator*=(Mint rhs) {
        for (Mint& value : *this) value *= rhs;
        return *this;
    }

    Fps& operator/=(Mint rhs) {
        return *this *= rhs.inv();
    }

    Fps& operator<<=(int shift) {
        assert(shift >= 0);
        this->insert(this->begin(), shift, Mint(0));
        return *this;
    }

    Fps& operator>>=(int shift) {
        assert(shift >= 0);
        if (shift >= int(this->size())) {
            this->clear();
        } else {
            this->erase(this->begin(), this->begin() + shift);
        }
        return *this;
    }

    Fps operator+() const {
        return *this;
    }

    Fps operator-() const {
        Fps result = *this;
        for (Mint& value : result) value = Mint(0) - value;
        return result;
    }

    friend Fps operator+(Fps lhs, const Fps& rhs) {
        return lhs += rhs;
    }

    friend Fps operator-(Fps lhs, const Fps& rhs) {
        return lhs -= rhs;
    }

    friend Fps operator*(Fps lhs, const Fps& rhs) {
        return lhs *= rhs;
    }

    friend Fps operator*(Fps lhs, Mint rhs) {
        return lhs *= rhs;
    }

    friend Fps operator*(Mint lhs, Fps rhs) {
        return rhs *= lhs;
    }

    friend Fps operator/(Fps lhs, Mint rhs) {
        return lhs /= rhs;
    }

    friend Fps operator<<(Fps lhs, int shift) {
        return lhs <<= shift;
    }

    friend Fps operator>>(Fps lhs, int shift) {
        return lhs >>= shift;
    }

    Fps derivative() const {
        if (this->empty()) return {};
        Fps result(this->size() - 1);
        for (int i = 1; i < int(this->size()); i++) result[i - 1] = (*this)[i] * Mint(i);
        return result;
    }

    Fps integral() const {
        Fps result(this->size() + 1);
        if (this->empty()) return result;
        assert(this->size() < Mint::mod());

        std::vector<Mint> inverse(this->size() + 1);
        inverse[1] = 1;
        for (int i = 2; i <= int(this->size()); i++) {
            inverse[i] = Mint(0) - Mint(Mint::mod() / uint32_t(i)) * inverse[Mint::mod() % uint32_t(i)];
        }
        for (int i = 0; i < int(this->size()); i++) result[i + 1] = (*this)[i] * inverse[i + 1];
        return result;
    }

    Mint evaluate(Mint x) const {
        Mint result = 0;
        for (auto it = this->rbegin(); it != this->rend(); ++it) result = result * x + *it;
        return result;
    }

    Fps inv(int degree = -1) const {
        if (degree < 0) degree = int(this->size());
        assert(degree >= 0);
        if (degree == 0) return {};
        assert(!this->empty() && (*this)[0] != Mint(0));

        Fps result(1, (*this)[0].inv());
        for (int size = 1; size < degree; size <<= 1) {
            const int next_size = std::min(size << 1, degree);
            const int transform_size = size << 1;
            if (size >= 32 && (Mint::mod() - 1) % uint32_t(transform_size) == 0) {
                // Newton's g <- g(2-fg), restricted to the newly determined
                // half.  Keeping g in the frequency domain avoids two general
                // convolutions and their 2x larger padding.
                std::vector<Mint> transformed_f(transform_size);
                std::copy_n(this->begin(), std::min<int>(this->size(), next_size),
                            transformed_f.begin());
                std::vector<Mint> transformed_g(transform_size);
                std::copy(result.begin(), result.end(), transformed_g.begin());
                internal::ntt(transformed_f, false);
                internal::ntt(transformed_g, false);

                std::vector<Mint> error(transform_size);
                for (int i = 0; i < transform_size; i++)
                    error[i] = transformed_f[i] * transformed_g[i];
                internal::ntt(error, true);
                std::fill(error.begin(), error.begin() + size, Mint(0));
                internal::ntt(error, false);
                for (int i = 0; i < transform_size; i++) error[i] *= transformed_g[i];
                internal::ntt(error, true);

                result.resize(next_size);
                for (int i = size; i < next_size; i++) result[i] = Mint(0) - error[i];
                continue;
            }
            Fps product = this->pre(next_size) * result;
            product.resize(next_size);
            for (Mint& value : product) value = Mint(0) - value;
            product[0] += Mint(2);
            result = (result * product).pre(next_size);
        }
        return result.pre(degree);
    }

    Fps log(int degree = -1) const {
        if (degree < 0) degree = int(this->size());
        assert(degree >= 0);
        if (degree == 0) return {};
        assert(!this->empty() && (*this)[0] == Mint(1));
        return (derivative() * inv(degree)).pre(degree - 1).integral();
    }

    Fps exp(int degree = -1) const {
        if (degree < 0) degree = int(this->size());
        assert(degree >= 0);
        if (degree == 0) return {};
        assert(this->empty() || (*this)[0] == Mint(0));

        Fps result(1, Mint(1));
        for (int size = 1; size < degree; size <<= 1) {
            const int next_size = std::min(size << 1, degree);
            Fps correction = this->pre(next_size) - result.log(next_size);
            correction[0] += Mint(1);
            result = (result * correction).pre(next_size);
        }
        return result.pre(degree);
    }

    Fps pow(long long exponent, int degree = -1) const {
        if (degree < 0) degree = int(this->size());
        assert(exponent >= 0 && degree >= 0);
        if (degree == 0) return {};
        if (exponent == 0) {
            Fps result(degree);
            result[0] = 1;
            return result;
        }

        int first = 0;
        while (first < int(this->size()) && (*this)[first] == Mint(0)) first++;
        if (first == int(this->size()) || first > (degree - 1) / exponent) return Fps(degree);

        const int shift = int(first * exponent);
        const Mint leading = (*this)[first];
        Fps normalized = (*this >> first) / leading;
        Fps result = (normalized.log(degree - shift) * Mint(exponent)).exp(degree - shift);
        result *= leading.pow(exponent);
        result <<= shift;
        result.resize(degree);
        return result;
    }

    std::optional<Fps> sqrt(int degree = -1) const {
        if (degree < 0) degree = int(this->size());
        assert(degree >= 0);
        if (degree == 0) return Fps();

        int first = 0;
        while (first < int(this->size()) && (*this)[first] == Mint(0)) first++;
        if (first == int(this->size())) return Fps(degree);
        if (first >= degree) return Fps(degree);
        if (first & 1) return std::nullopt;

        const int shift = first / 2;
        auto leading_root = m1une::math::modular_square_root((*this)[first]);
        if (!leading_root.has_value()) return std::nullopt;

        const int result_degree = degree - shift;
        Fps normalized = (*this >> first) / (*this)[first];
        Fps result = (normalized.log(result_degree) / Mint(2)).exp(result_degree);
        result *= *leading_root;
        result <<= shift;
        result.resize(degree);
        return result;
    }

    std::pair<Fps, Fps> divmod(const Fps& divisor) const {
        Fps dividend = *this;
        Fps normalized_divisor = divisor;
        dividend.shrink();
        normalized_divisor.shrink();
        assert(!normalized_divisor.empty());

        if (dividend.size() < normalized_divisor.size()) return std::make_pair(Fps(), dividend);
        const int quotient_size = int(dividend.size() - normalized_divisor.size() + 1);
        Fps quotient =
            (dividend.reversed().pre(quotient_size) * normalized_divisor.reversed().inv(quotient_size))
                .pre(quotient_size)
                .reversed();
        quotient.shrink();
        Fps remainder = dividend - normalized_divisor * quotient;
        remainder.resize(normalized_divisor.size() - 1);
        remainder.shrink();
        return std::make_pair(std::move(quotient), std::move(remainder));
    }

    Fps& operator/=(const Fps& rhs) {
        *this = divmod(rhs).first;
        return *this;
    }

    Fps& operator%=(const Fps& rhs) {
        *this = divmod(rhs).second;
        return *this;
    }

    friend Fps operator/(Fps lhs, const Fps& rhs) {
        return lhs /= rhs;
    }

    friend Fps operator%(Fps lhs, const Fps& rhs) {
        return lhs %= rhs;
    }

    Fps taylor_shift(Mint shift) const {
        const int n = int(this->size());
        if (n == 0) return {};
        assert(uint32_t(n) < Mint::mod());

        std::vector<Mint> factorial(n, Mint(1));
        std::vector<Mint> inverse_factorial(n, Mint(1));
        for (int i = 1; i < n; i++) factorial[i] = factorial[i - 1] * Mint(i);
        inverse_factorial[n - 1] = factorial[n - 1].inv();
        for (int i = n - 1; i > 0; i--) inverse_factorial[i - 1] = inverse_factorial[i] * Mint(i);

        Fps left(n);
        Fps right(n);
        Mint power = 1;
        for (int i = 0; i < n; i++) {
            left[n - 1 - i] = (*this)[i] * factorial[i];
            right[i] = power * inverse_factorial[i];
            power *= shift;
        }
        Fps product = left * right;
        Fps result(n);
        for (int i = 0; i < n; i++) result[i] = product[n - 1 - i] * inverse_factorial[i];
        return result;
    }
};

}  // namespace fps
}  // namespace m1une


#line 1 "math/combinatorics.hpp"



#line 7 "math/combinatorics.hpp"

namespace m1une {
namespace math {

template <class Mint>
struct Combinatorics {
   private:
    std::vector<Mint> _factorial;
    std::vector<Mint> _inverse_factorial;

   public:
    explicit Combinatorics(int maximum = 0) : _factorial(1, Mint(1)), _inverse_factorial(1, Mint(1)) {
        ensure(maximum);
    }

    int maximum() const {
        return int(_factorial.size()) - 1;
    }

    void ensure(int maximum) {
        assert(maximum >= 0);
        assert(static_cast<uint64_t>(maximum) < Mint::mod());
        if (maximum <= this->maximum()) return;

        const int old_maximum = this->maximum();
        _factorial.resize(maximum + 1);
        _inverse_factorial.resize(maximum + 1);
        for (int i = old_maximum + 1; i <= maximum; i++) {
            _factorial[i] = _factorial[i - 1] * Mint(i);
        }
        _inverse_factorial[maximum] = _factorial[maximum].inv();
        for (int i = maximum; i > old_maximum; i--) {
            _inverse_factorial[i - 1] = _inverse_factorial[i] * Mint(i);
        }
    }

    Mint factorial(int n) const {
        assert(0 <= n && n <= maximum());
        return _factorial[n];
    }

    Mint inverse_factorial(int n) const {
        assert(0 <= n && n <= maximum());
        return _inverse_factorial[n];
    }

    Mint inverse(int n) const {
        assert(1 <= n && n <= maximum());
        return _factorial[n - 1] * _inverse_factorial[n];
    }

    Mint binom(int n, int k) const {
        if (k < 0 || k > n) return Mint(0);
        assert(n <= maximum());
        return _factorial[n] * _inverse_factorial[k] * _inverse_factorial[n - k];
    }

    Mint perm(int n, int k) const {
        if (k < 0 || k > n) return Mint(0);
        assert(n <= maximum());
        return _factorial[n] * _inverse_factorial[n - k];
    }

    Mint multiset(int types, int count) const {
        if (types < 0 || count < 0) return Mint(0);
        if (types == 0) return Mint(count == 0);
        const long long total = static_cast<long long>(types) + count - 1;
        assert(total <= maximum());
        return binom(static_cast<int>(total), count);
    }

    Mint catalan(int n) const {
        assert(n >= 0);
        const long long doubled = 2LL * n;
        assert(doubled <= maximum());
        return binom(int(doubled), n) - binom(int(doubled), n + 1);
    }
};

}  // namespace math
}  // namespace m1une


#line 10 "math/bernoulli.hpp"

namespace m1une {
namespace math {

namespace bernoulli_detail {

template <class Mint>
std::vector<Mint> numbers(
    int maximum,
    const Combinatorics<Mint>& combinations
) {
    using Fps = fps::FormalPowerSeries<Mint>;
    Fps denominator(maximum + 1);
    for (int index = 0; index <= maximum; ++index) {
        denominator[index] = combinations.inverse_factorial(index + 1);
    }

    Fps generating_function = denominator.inv(maximum + 1);
    std::vector<Mint> result(maximum + 1);
    for (int index = 0; index <= maximum; ++index) {
        result[index] =
            generating_function[index] * combinations.factorial(index);
    }
    return result;
}

template <class Mint>
Mint evaluate_polynomial(const std::vector<Mint>& coefficients, Mint x) {
    Mint result = 0;
    for (int index = int(coefficients.size()) - 1; index >= 0; --index) {
        result = result * x + coefficients[index];
    }
    return result;
}

}  // namespace bernoulli_detail

// Uses x / (exp(x) - 1), so B_1 = -1/2.
template <class Mint>
std::vector<Mint> bernoulli_numbers(int maximum) {
    assert(maximum >= 0);
    assert(static_cast<uint64_t>(maximum) + 1 < Mint::mod());
    Combinatorics<Mint> combinations(maximum + 1);
    return bernoulli_detail::numbers(maximum, combinations);
}

template <class Mint>
class Bernoulli {
   public:
    explicit Bernoulli(int maximum)
        : combinations_(checked_maximum(maximum) + 1),
          numbers_(bernoulli_detail::numbers(maximum, combinations_)) {}

    int maximum() const {
        return int(numbers_.size()) - 1;
    }

    const std::vector<Mint>& numbers() const {
        return numbers_;
    }

    Mint number(int degree) const {
        assert(0 <= degree && degree <= maximum());
        return numbers_[degree];
    }

    // Coefficients of B_degree(x), in increasing order of powers of x.
    std::vector<Mint> polynomial_coefficients(int degree) const {
        assert(0 <= degree && degree <= maximum());
        std::vector<Mint> result(degree + 1);
        for (int power = 0; power <= degree; ++power) {
            result[power] =
                combinations_.binom(degree, power) *
                numbers_[degree - power];
        }
        return result;
    }

    Mint polynomial(int degree, Mint x) const {
        assert(0 <= degree && degree <= maximum());
        std::vector<Mint> powers(degree + 1, Mint(1));
        for (int power = 0; power < degree; ++power) {
            powers[power + 1] = powers[power] * x;
        }

        Mint result = 0;
        for (int index = 0; index <= degree; ++index) {
            result += combinations_.binom(degree, index) * numbers_[index] *
                      powers[degree - index];
        }
        return result;
    }

    // Returns sum_{i=0}^{n-1} i^degree, evaluated as a polynomial in n.
    Mint power_sum(Mint n, int degree) const {
        assert(0 <= degree && degree <= maximum());
        std::vector<Mint> powers(degree + 2, Mint(1));
        for (int power = 0; power <= degree; ++power) {
            powers[power + 1] = powers[power] * n;
        }

        Mint result = 0;
        for (int index = 0; index <= degree; ++index) {
            result += combinations_.binom(degree + 1, index) *
                      numbers_[index] * powers[degree + 1 - index];
        }
        return result * combinations_.inverse(degree + 1);
    }

    // Returns sum_{i=left}^{right-1} i^degree.
    Mint power_sum(Mint left, Mint right, int degree) const {
        return power_sum(right, degree) - power_sum(left, degree);
    }

    // Coefficients of sum_{i=0}^{n-1} i^degree as a polynomial in n.
    std::vector<Mint> power_sum_polynomial(int degree) const {
        assert(0 <= degree && degree <= maximum());
        std::vector<Mint> result(degree + 2);
        Mint inverse = combinations_.inverse(degree + 1);
        for (int index = 0; index <= degree; ++index) {
            result[degree + 1 - index] +=
                combinations_.binom(degree + 1, index) * numbers_[index] *
                inverse;
        }
        return result;
    }

    // If P is given by coefficients, returns coefficients of the unique Q
    // with Q(0) = 0 and Q(n) = sum_{i=0}^{n-1} P(i).
    std::vector<Mint> polynomial_prefix_sum(
        const std::vector<Mint>& coefficients
    ) const {
        if (coefficients.empty()) return std::vector<Mint>{Mint(0)};
        int degree = int(coefficients.size()) - 1;
        assert(degree <= maximum());

        std::vector<Mint> result(degree + 2);
        for (int source_degree = 0;
             source_degree <= degree;
             ++source_degree) {
            Mint inverse = combinations_.inverse(source_degree + 1);
            for (int index = 0; index <= source_degree; ++index) {
                result[source_degree + 1 - index] +=
                    coefficients[source_degree] *
                    combinations_.binom(source_degree + 1, index) *
                    numbers_[index] * inverse;
            }
        }
        return result;
    }

    // Returns sum_{i=left}^{right-1} P(i).
    Mint polynomial_sum(
        const std::vector<Mint>& coefficients,
        Mint left,
        Mint right
    ) const {
        std::vector<Mint> prefix = polynomial_prefix_sum(coefficients);
        return bernoulli_detail::evaluate_polynomial(prefix, right) -
               bernoulli_detail::evaluate_polynomial(prefix, left);
    }

    // Returns sum_{i=0}^{count-1} (start + step*i)^degree.
    Mint arithmetic_progression_power_sum(
        Mint start,
        Mint step,
        Mint count,
        int degree
    ) const {
        assert(0 <= degree && degree <= maximum());
        std::vector<Mint> start_powers(degree + 1, Mint(1));
        std::vector<Mint> step_powers(degree + 1, Mint(1));
        for (int power = 0; power < degree; ++power) {
            start_powers[power + 1] = start_powers[power] * start;
            step_powers[power + 1] = step_powers[power] * step;
        }

        Mint result = 0;
        for (int power = 0; power <= degree; ++power) {
            result += combinations_.binom(degree, power) *
                      start_powers[degree - power] * step_powers[power] *
                      power_sum(count, power);
        }
        return result;
    }

   private:
    static int checked_maximum(int maximum) {
        assert(maximum >= 0);
        assert(static_cast<uint64_t>(maximum) + 1 < Mint::mod());
        return maximum;
    }

    Combinatorics<Mint> combinations_;
    std::vector<Mint> numbers_;
};

}  // namespace math
}  // namespace m1une


#line 1 "math/binomial_coefficient_mod.hpp"



#line 8 "math/binomial_coefficient_mod.hpp"

#line 1 "math/number_theory.hpp"



#line 7 "math/number_theory.hpp"
#include <tuple>
#line 10 "math/number_theory.hpp"

namespace m1une {
namespace math {

namespace internal {

inline long long safe_mod(long long x, long long mod) {
    x %= mod;
    if (x < 0) x += mod;
    return x;
}

inline unsigned __int128 floor_sum_unsigned(unsigned long long n, unsigned long long mod, unsigned long long a,
                                            unsigned long long b) {
    unsigned __int128 answer = 0;
    while (true) {
        if (a >= mod) {
            answer += static_cast<unsigned __int128>(n) * (n - 1) / 2 * (a / mod);
            a %= mod;
        }
        if (b >= mod) {
            answer += static_cast<unsigned __int128>(n) * (b / mod);
            b %= mod;
        }

        const unsigned __int128 y_max = static_cast<unsigned __int128>(a) * n + b;
        if (y_max < mod) break;
        n = static_cast<unsigned long long>(y_max / mod);
        b = static_cast<unsigned long long>(y_max % mod);
        unsigned long long tmp = mod;
        mod = a;
        a = tmp;
    }
    return answer;
}

}  // namespace internal

// Returns (g, x, y), where g = gcd(a, b) is nonnegative and
// a * x + b * y = g. Returns (0, 0, 0) when a = b = 0.
inline std::tuple<long long, long long, long long> extended_gcd(long long a,
                                                               long long b) {
    using i128 = __int128;
    if (a == 0 && b == 0) return {0, 0, 0};

    i128 old_remainder = a;
    i128 remainder = b;
    if (old_remainder < 0) old_remainder = -old_remainder;
    if (remainder < 0) remainder = -remainder;
    i128 old_x = 1;
    i128 x = 0;
    i128 old_y = 0;
    i128 y = 1;

    while (remainder != 0) {
        i128 quotient = old_remainder / remainder;

        i128 next = old_remainder - quotient * remainder;
        old_remainder = remainder;
        remainder = next;

        next = old_x - quotient * x;
        old_x = x;
        x = next;

        next = old_y - quotient * y;
        old_y = y;
        y = next;
    }

    if (a < 0) old_x = -old_x;
    if (b < 0) old_y = -old_y;

#ifndef NDEBUG
    const i128 minimum = std::numeric_limits<long long>::min();
    const i128 maximum = std::numeric_limits<long long>::max();
    assert(old_remainder <= maximum);
    assert(minimum <= old_x && old_x <= maximum);
    assert(minimum <= old_y && old_y <= maximum);
#endif
    return {static_cast<long long>(old_remainder), static_cast<long long>(old_x),
            static_cast<long long>(old_y)};
}

inline long long pow_mod(long long x, unsigned long long exponent, long long mod) {
    assert(mod >= 1);
    if (mod == 1) return 0;

    unsigned long long base = static_cast<unsigned long long>(internal::safe_mod(x, mod));
    unsigned long long result = 1;
    const unsigned long long unsigned_mod = static_cast<unsigned long long>(mod);
    while (exponent > 0) {
        if (exponent & 1) {
            result = static_cast<unsigned long long>(static_cast<unsigned __int128>(result) * base % unsigned_mod);
        }
        base = static_cast<unsigned long long>(static_cast<unsigned __int128>(base) * base % unsigned_mod);
        exponent >>= 1;
    }
    return static_cast<long long>(result);
}

// Returns gcd(a, mod) and x such that a * x is congruent to gcd(a, mod)
// modulo mod. The returned x is in [0, mod / gcd(a, mod)).
inline std::pair<long long, long long> inv_gcd(long long a, long long mod) {
    assert(mod >= 1);
    a = internal::safe_mod(a, mod);
    if (a == 0) return {mod, 0};

    long long s = mod;
    long long t = a;
    long long m0 = 0;
    long long m1 = 1;
    while (t > 0) {
        const long long quotient = s / t;
        s -= t * quotient;
        m0 -= m1 * quotient;

        long long tmp = s;
        s = t;
        t = tmp;
        tmp = m0;
        m0 = m1;
        m1 = tmp;
    }
    if (m0 < 0) m0 += mod / s;
    return {s, m0};
}

inline long long inv_mod(long long x, long long mod) {
    const auto result = inv_gcd(x, mod);
    assert(result.first == 1);
    return result.second;
}

// Returns the smallest nonnegative solution and the least common multiple of
// the moduli. Returns {0, 0} when the system is inconsistent.
inline std::pair<long long, long long> crt(const std::vector<long long>& remainders,
                                           const std::vector<long long>& moduli) {
    assert(remainders.size() == moduli.size());

    long long r0 = 0;
    long long m0 = 1;
    for (int i = 0; i < int(remainders.size()); i++) {
        assert(moduli[i] >= 1);
        long long r1 = internal::safe_mod(remainders[i], moduli[i]);
        long long m1 = moduli[i];

        if (m0 < m1) {
            long long tmp = r0;
            r0 = r1;
            r1 = tmp;
            tmp = m0;
            m0 = m1;
            m1 = tmp;
        }
        if (m0 % m1 == 0) {
            if (r0 % m1 != r1) return {0, 0};
            continue;
        }

        const auto inverse = inv_gcd(m0, m1);
        const long long gcd = inverse.first;
        const long long reduced_modulus = m1 / gcd;
        const __int128 difference = static_cast<__int128>(r1) - r0;
        if (difference % gcd != 0) return {0, 0};

        __int128 multiplier = difference / gcd % reduced_modulus;
        multiplier = multiplier * inverse.second % reduced_modulus;
        if (multiplier < 0) multiplier += reduced_modulus;

        const __int128 new_modulus = static_cast<__int128>(m0) * reduced_modulus;
        assert(new_modulus <= std::numeric_limits<long long>::max());
        __int128 new_remainder = static_cast<__int128>(r0) + multiplier * m0;
        new_remainder %= new_modulus;
        if (new_remainder < 0) new_remainder += new_modulus;
        r0 = static_cast<long long>(new_remainder);
        m0 = static_cast<long long>(new_modulus);
    }
    return {r0, m0};
}

// Returns sum_{i=0}^{n-1} floor((a * i + b) / mod).
inline long long floor_sum(long long n, long long mod, long long a, long long b) {
    assert(n >= 0);
    assert(mod >= 1);

    const long long normalized_a = internal::safe_mod(a, mod);
    const long long normalized_b = internal::safe_mod(b, mod);
    __int128 answer = (static_cast<__int128>(a) - normalized_a) / mod * n * (n - 1) / 2;
    answer += (static_cast<__int128>(b) - normalized_b) / mod * n;
    answer += internal::floor_sum_unsigned(static_cast<unsigned long long>(n), static_cast<unsigned long long>(mod),
                                           static_cast<unsigned long long>(normalized_a),
                                           static_cast<unsigned long long>(normalized_b));

    assert(answer >= std::numeric_limits<long long>::min());
    assert(answer <= std::numeric_limits<long long>::max());
    return static_cast<long long>(answer);
}

}  // namespace math
}  // namespace m1une


#line 10 "math/binomial_coefficient_mod.hpp"

namespace m1une {
namespace math {

// Binomial coefficients modulo a fixed, not necessarily prime, modulus.
class BinomialCoefficientMod {
   private:
    struct PrimePower {
        uint32_t prime;
        int exponent;
        uint32_t modulus;
        uint32_t crt_multiplier;
        std::vector<uint32_t> unit_factorial_prefix;

        uint32_t multiply(uint32_t lhs, uint32_t rhs) const {
            return uint32_t(uint64_t(lhs) * rhs % modulus);
        }

        uint32_t power(uint32_t base, uint64_t exponent_) const {
            uint32_t result = 1 % modulus;
            while (exponent_ > 0) {
                if (exponent_ & 1) result = multiply(result, base);
                base = multiply(base, base);
                exponent_ >>= 1;
            }
            return result;
        }

        uint64_t factorial_valuation(uint64_t n) const {
            uint64_t result = 0;
            while (n > 0) {
                n /= prime;
                result += n;
            }
            return result;
        }

        uint32_t unit_factorial(uint64_t n) const {
            if (n == 0) return 1 % modulus;
            const uint32_t block_product = unit_factorial_prefix.back();
            uint32_t result = power(block_product, n / modulus);
            result = multiply(result, unit_factorial_prefix[std::size_t(n % modulus)]);
            return multiply(result, unit_factorial(n / prime));
        }

        uint32_t binom(uint64_t n, uint64_t k) const {
            if (k > n) return 0;
            const uint64_t valuation = factorial_valuation(n) - factorial_valuation(k) -
                                       factorial_valuation(n - k);
            if (valuation >= uint64_t(exponent)) return 0;

            const uint32_t numerator = unit_factorial(n);
            const uint32_t denominator =
                multiply(unit_factorial(k), unit_factorial(n - k));
            const uint32_t inverse_denominator =
                uint32_t(inv_mod(denominator, modulus));
            uint32_t result = multiply(numerator, inverse_denominator);
            result = multiply(result, power(prime, valuation));
            return result;
        }
    };

    uint32_t _modulus;
    std::vector<PrimePower> _prime_powers;

   public:
    explicit BinomialCoefficientMod(uint32_t modulus) : _modulus(modulus) {
        assert(modulus >= 1);
        uint32_t remaining = modulus;
        for (uint32_t prime = 2; uint64_t(prime) * prime <= remaining; prime++) {
            if (remaining % prime != 0) continue;
            int exponent = 0;
            uint32_t prime_power = 1;
            do {
                remaining /= prime;
                prime_power *= prime;
                exponent++;
            } while (remaining % prime == 0);
            _prime_powers.push_back(
                PrimePower{prime, exponent, prime_power, 0, {}});
        }
        if (remaining > 1) {
            _prime_powers.push_back(PrimePower{remaining, 1, remaining, 0, {}});
        }

        for (PrimePower& component : _prime_powers) {
            component.unit_factorial_prefix.resize(std::size_t(component.modulus));
            component.unit_factorial_prefix[0] = 1;
            for (uint32_t value = 1; value < component.modulus; value++) {
                component.unit_factorial_prefix[value] =
                    component.unit_factorial_prefix[value - 1];
                if (value % component.prime != 0) {
                    component.unit_factorial_prefix[value] = component.multiply(
                        component.unit_factorial_prefix[value], value);
                }
            }

            const uint32_t other = modulus / component.modulus;
            const uint32_t inverse =
                uint32_t(inv_mod(other, component.modulus));
            component.crt_multiplier =
                uint32_t(uint64_t(other) * inverse % modulus);
        }
    }

    uint32_t modulus() const {
        return _modulus;
    }

    uint32_t binom(uint64_t n, uint64_t k) const {
        if (k > n || _modulus == 1) return 0;
        uint64_t result = 0;
        for (const PrimePower& component : _prime_powers) {
            const uint32_t residue = component.binom(n, k);
            result += uint64_t(residue) * component.crt_multiplier % _modulus;
            result %= _modulus;
        }
        return uint32_t(result);
    }

    uint32_t operator()(uint64_t n, uint64_t k) const {
        return binom(n, k);
    }
};

using ArbitraryModBinomialCoefficient = BinomialCoefficientMod;

}  // namespace math
}  // namespace m1une


#line 1 "math/bitwise_convolution.hpp"



#line 8 "math/bitwise_convolution.hpp"

#line 1 "math/zeta_mobius_transform.hpp"



#line 7 "math/zeta_mobius_transform.hpp"

namespace m1une {
namespace math {

namespace zeta_mobius_transform_detail {

inline bool is_power_of_two(std::size_t size) noexcept {
    return size != 0 && (size & (size - 1)) == 0;
}

inline std::vector<std::size_t> primes_up_to(std::size_t limit) {
    std::vector<std::size_t> primes;
    std::vector<bool> is_prime(limit + 1, true);
    if (!is_prime.empty()) is_prime[0] = false;
    if (limit >= 1) is_prime[1] = false;
    for (std::size_t value = 2; value <= limit; ++value) {
        if (!is_prime[value]) continue;
        primes.emplace_back(value);
        if (value > limit / value) continue;
        for (
            std::size_t multiple = value * value;
            multiple <= limit;
            multiple += value
        ) {
            is_prime[multiple] = false;
        }
    }
    return primes;
}

}  // namespace zeta_mobius_transform_detail

template <typename T>
void subset_zeta_transform(std::vector<T>& values) {
    assert(zeta_mobius_transform_detail::is_power_of_two(values.size()));
    for (std::size_t bit = 1; bit < values.size(); bit <<= 1) {
        for (
            std::size_t block = 0;
            block < values.size();
            block += bit << 1
        ) {
            for (std::size_t offset = 0; offset < bit; ++offset) {
                values[block + bit + offset] += values[block + offset];
            }
        }
    }
}

template <typename T>
void subset_mobius_transform(std::vector<T>& values) {
    assert(zeta_mobius_transform_detail::is_power_of_two(values.size()));
    for (std::size_t bit = 1; bit < values.size(); bit <<= 1) {
        for (
            std::size_t block = 0;
            block < values.size();
            block += bit << 1
        ) {
            for (std::size_t offset = 0; offset < bit; ++offset) {
                values[block + bit + offset] -= values[block + offset];
            }
        }
    }
}

template <typename T>
void superset_zeta_transform(std::vector<T>& values) {
    assert(zeta_mobius_transform_detail::is_power_of_two(values.size()));
    for (std::size_t bit = 1; bit < values.size(); bit <<= 1) {
        for (
            std::size_t block = 0;
            block < values.size();
            block += bit << 1
        ) {
            for (std::size_t offset = 0; offset < bit; ++offset) {
                values[block + offset] += values[block + bit + offset];
            }
        }
    }
}

template <typename T>
void superset_mobius_transform(std::vector<T>& values) {
    assert(zeta_mobius_transform_detail::is_power_of_two(values.size()));
    for (std::size_t bit = 1; bit < values.size(); bit <<= 1) {
        for (
            std::size_t block = 0;
            block < values.size();
            block += bit << 1
        ) {
            for (std::size_t offset = 0; offset < bit; ++offset) {
                values[block + offset] -= values[block + bit + offset];
            }
        }
    }
}

template <typename T>
void divisor_zeta_transform(std::vector<T>& values) {
    if (values.size() <= 2) return;
    const std::size_t limit = values.size() - 1;
    const std::vector<std::size_t> primes =
        zeta_mobius_transform_detail::primes_up_to(limit);
    for (std::size_t prime : primes) {
        for (std::size_t value = 1; value <= limit / prime; ++value) {
            values[value * prime] += values[value];
        }
    }
}

template <typename T>
void divisor_mobius_transform(std::vector<T>& values) {
    if (values.size() <= 2) return;
    const std::size_t limit = values.size() - 1;
    const std::vector<std::size_t> primes =
        zeta_mobius_transform_detail::primes_up_to(limit);
    for (std::size_t prime : primes) {
        for (
            std::size_t value = limit / prime;
            value >= 1;
            --value
        ) {
            values[value * prime] -= values[value];
        }
    }
}

template <typename T>
void multiple_zeta_transform(std::vector<T>& values) {
    if (values.size() <= 2) return;
    const std::size_t limit = values.size() - 1;
    const std::vector<std::size_t> primes =
        zeta_mobius_transform_detail::primes_up_to(limit);
    for (std::size_t prime : primes) {
        for (
            std::size_t value = limit / prime;
            value >= 1;
            --value
        ) {
            values[value] += values[value * prime];
        }
    }
}

template <typename T>
void multiple_mobius_transform(std::vector<T>& values) {
    if (values.size() <= 2) return;
    const std::size_t limit = values.size() - 1;
    const std::vector<std::size_t> primes =
        zeta_mobius_transform_detail::primes_up_to(limit);
    for (std::size_t prime : primes) {
        for (std::size_t value = 1; value <= limit / prime; ++value) {
            values[value] -= values[value * prime];
        }
    }
}

}  // namespace math
}  // namespace m1une


#line 10 "math/bitwise_convolution.hpp"

namespace m1une {
namespace math {

namespace bitwise_convolution_detail {

inline std::size_t common_size(
    std::size_t first_size,
    std::size_t second_size
) {
    std::size_t required = first_size > second_size
        ? first_size
        : second_size;
    std::size_t size = 1;
    while (size < required) size <<= 1;
    return size;
}

template <typename T>
std::vector<T> pointwise_product(
    std::vector<T> first,
    const std::vector<T>& second
) {
    assert(first.size() == second.size());
    for (std::size_t index = 0; index < first.size(); ++index) {
        first[index] *= second[index];
    }
    return first;
}

}  // namespace bitwise_convolution_detail

template <typename T>
void walsh_hadamard_transform(
    std::vector<T>& values,
    bool inverse = false
) {
    assert(zeta_mobius_transform_detail::is_power_of_two(values.size()));
    for (std::size_t length = 1; length < values.size(); length <<= 1) {
        for (
            std::size_t block = 0;
            block < values.size();
            block += length << 1
        ) {
            for (std::size_t offset = 0; offset < length; ++offset) {
                T first = values[block + offset];
                T second = values[block + offset + length];
                values[block + offset] = first + second;
                values[block + offset + length] = first - second;
            }
        }
    }
    if (inverse) {
        T size = T(static_cast<long long>(values.size()));
        for (T& value : values) value /= size;
    }
}

template <typename T>
std::vector<T> bitwise_or_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    if (first.empty() || second.empty()) return {};
    std::size_t size = bitwise_convolution_detail::common_size(
        first.size(),
        second.size()
    );
    first.resize(size);
    second.resize(size);
    subset_zeta_transform(first);
    subset_zeta_transform(second);
    first = bitwise_convolution_detail::pointwise_product(
        std::move(first),
        second
    );
    subset_mobius_transform(first);
    return first;
}

template <typename T>
std::vector<T> bitwise_and_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    if (first.empty() || second.empty()) return {};
    std::size_t size = bitwise_convolution_detail::common_size(
        first.size(),
        second.size()
    );
    first.resize(size);
    second.resize(size);
    superset_zeta_transform(first);
    superset_zeta_transform(second);
    first = bitwise_convolution_detail::pointwise_product(
        std::move(first),
        second
    );
    superset_mobius_transform(first);
    return first;
}

template <typename T>
std::vector<T> bitwise_xor_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    if (first.empty() || second.empty()) return {};
    std::size_t size = bitwise_convolution_detail::common_size(
        first.size(),
        second.size()
    );
    first.resize(size);
    second.resize(size);
    walsh_hadamard_transform(first);
    walsh_hadamard_transform(second);
    first = bitwise_convolution_detail::pointwise_product(
        std::move(first),
        second
    );
    walsh_hadamard_transform(first, true);
    return first;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/bit_ceil.hpp"



namespace m1une {
namespace math {

template <typename T>
constexpr T bit_ceil(T n) {
    if (n <= 1) return 1;
    T x = 1;
    while (x < n) x <<= 1;
    return x;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/combinatorial_sequences.hpp"



#line 7 "math/combinatorial_sequences.hpp"

#line 1 "math/partition_function.hpp"



#line 5 "math/partition_function.hpp"

#line 8 "math/partition_function.hpp"

namespace m1une {
namespace math {

// Returns p(0), p(1), ..., p(maximum), where p(n) is the number of integer
// partitions of n.
template <class Mint>
std::vector<Mint> partition_function(int maximum) {
    assert(maximum >= 0);

    using Fps = fps::FormalPowerSeries<Mint>;
    Fps denominator(maximum + 1);
    denominator[0] = 1;
    for (long long k = 1;; k++) {
        long long first = k * (3 * k - 1) / 2;
        long long second = k * (3 * k + 1) / 2;
        if (first > maximum) break;

        Mint sign = (k & 1) ? Mint(-1) : Mint(1);
        denominator[int(first)] += sign;
        if (second <= maximum) denominator[int(second)] += sign;
    }
    return denominator.inv(maximum + 1);
}

template <class Mint>
std::vector<Mint> partition_numbers(int maximum) {
    return partition_function<Mint>(maximum);
}

}  // namespace math
}  // namespace m1une


#line 12 "math/combinatorial_sequences.hpp"

namespace m1une {
namespace math {

template <class Mint>
std::vector<Mint> catalan_numbers(int maximum) {
    assert(maximum >= 0);
    assert(static_cast<uint64_t>(maximum) + 1 < Mint::mod());

    std::vector<Mint> inverse(maximum + 2);
    inverse[1] = 1;
    for (int i = 2; i <= maximum + 1; i++) {
        inverse[i] = Mint(0) - Mint(Mint::mod() / uint32_t(i)) * inverse[Mint::mod() % uint32_t(i)];
    }

    std::vector<Mint> result(maximum + 1);
    result[0] = 1;
    for (int n = 0; n < maximum; n++) {
        result[n + 1] = result[n] * Mint(2) * Mint(2LL * n + 1) * inverse[n + 2];
    }
    return result;
}

template <class Mint>
std::vector<Mint> bell_numbers(int maximum) {
    assert(maximum >= 0);
    assert(static_cast<uint64_t>(maximum) < Mint::mod());

    using Fps = fps::FormalPowerSeries<Mint>;
    Combinatorics<Mint> combinations(maximum);
    Fps exponent(maximum + 1);
    for (int i = 1; i <= maximum; i++) {
        exponent[i] = combinations.inverse_factorial(i);
    }

    Fps generating_function = exponent.exp(maximum + 1);
    std::vector<Mint> result(maximum + 1);
    for (int i = 0; i <= maximum; i++) {
        result[i] = generating_function[i] * combinations.factorial(i);
    }
    return result;
}

template <class Mint>
std::vector<Mint> stirling_numbers_second_kind(int n) {
    assert(n >= 0);
    assert(static_cast<uint64_t>(n) < Mint::mod());

    Combinatorics<Mint> combinations(n);
    std::vector<Mint> powers(n + 1);
    std::vector<Mint> signs(n + 1);
    for (int i = 0; i <= n; i++) {
        powers[i] = Mint(i).pow(n) * combinations.inverse_factorial(i);
        signs[i] = combinations.inverse_factorial(i);
        if (i & 1) signs[i] = Mint(0) - signs[i];
    }

    std::vector<Mint> result = fps::convolution(powers, signs);
    result.resize(n + 1);
    return result;
}

template <class Mint>
std::vector<Mint> derangement_numbers(int maximum) {
    assert(maximum >= 0);

    std::vector<Mint> result(maximum + 1);
    result[0] = 1;
    if (maximum >= 1) result[1] = 0;
    for (int n = 2; n <= maximum; n++) {
        result[n] = Mint(n - 1) * (result[n - 1] + result[n - 2]);
    }
    return result;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/cyclotomic_polynomial.hpp"



#line 9 "math/cyclotomic_polynomial.hpp"

#line 1 "math/prime_factorization.hpp"



#line 10 "math/prime_factorization.hpp"

namespace m1une {
namespace math {

namespace internal {

inline uint64_t multiply_mod(uint64_t a, uint64_t b, uint64_t mod) {
    return static_cast<uint64_t>(static_cast<unsigned __int128>(a) * b % mod);
}

inline uint64_t power_mod(uint64_t base, uint64_t exponent, uint64_t mod) {
    uint64_t result = 1;
    while (exponent > 0) {
        if (exponent & 1) result = multiply_mod(result, base, mod);
        base = multiply_mod(base, base, mod);
        exponent >>= 1;
    }
    return result;
}

inline uint64_t pollard_random() {
    static uint64_t state = 0x123456789abcdef0ULL;
    state += 0x9e3779b97f4a7c15ULL;
    uint64_t value = state;
    value = (value ^ (value >> 30)) * 0xbf58476d1ce4e5b9ULL;
    value = (value ^ (value >> 27)) * 0x94d049bb133111ebULL;
    return value ^ (value >> 31);
}

}  // namespace internal

inline bool is_prime(uint64_t value) {
    if (value < 2) return false;
    for (uint64_t prime : {2ULL, 3ULL, 5ULL, 7ULL, 11ULL, 13ULL, 17ULL, 19ULL, 23ULL, 29ULL, 31ULL, 37ULL}) {
        if (value % prime == 0) return value == prime;
    }

    uint64_t odd_part = value - 1;
    int power_of_two = 0;
    while ((odd_part & 1) == 0) {
        odd_part >>= 1;
        power_of_two++;
    }

    for (uint64_t base : {2ULL, 325ULL, 9375ULL, 28178ULL, 450775ULL, 9780504ULL, 1795265022ULL}) {
        if (base % value == 0) continue;
        uint64_t x = internal::power_mod(base % value, odd_part, value);
        if (x == 1 || x == value - 1) continue;

        bool composite = true;
        for (int i = 1; i < power_of_two; i++) {
            x = internal::multiply_mod(x, x, value);
            if (x == value - 1) {
                composite = false;
                break;
            }
        }
        if (composite) return false;
    }
    return true;
}

namespace internal {

inline uint64_t pollard_rho(uint64_t value) {
    for (uint64_t prime : {2ULL, 3ULL, 5ULL, 7ULL, 11ULL, 13ULL, 17ULL, 19ULL, 23ULL, 29ULL, 31ULL, 37ULL}) {
        if (value % prime == 0) return prime;
    }

    while (true) {
        const uint64_t constant = pollard_random() % (value - 1) + 1;
        uint64_t y = pollard_random() % (value - 1) + 1;
        uint64_t x = 0;
        uint64_t saved_y = 0;
        uint64_t gcd = 1;
        uint64_t segment_length = 1;

        auto advance = [&](uint64_t current) {
            return static_cast<uint64_t>(
                (static_cast<unsigned __int128>(multiply_mod(current, current, value)) + constant) % value);
        };

        while (gcd == 1) {
            x = y;
            for (uint64_t i = 0; i < segment_length; i++) y = advance(y);

            for (uint64_t offset = 0; offset < segment_length && gcd == 1; offset += 128) {
                saved_y = y;
                uint64_t product = 1;
                const uint64_t block = std::min<uint64_t>(128, segment_length - offset);
                for (uint64_t i = 0; i < block; i++) {
                    y = advance(y);
                    const uint64_t difference = x > y ? x - y : y - x;
                    product = multiply_mod(product, difference, value);
                }
                gcd = std::gcd(product, value);
            }
            segment_length <<= 1;
        }

        if (gcd == value) {
            do {
                saved_y = advance(saved_y);
                const uint64_t difference = x > saved_y ? x - saved_y : saved_y - x;
                gcd = std::gcd(difference, value);
            } while (gcd == 1);
        }
        if (gcd != value) return gcd;
    }
}

inline void factor_recursively(uint64_t value, std::vector<uint64_t>& factors) {
    if (value == 1) return;
    if (is_prime(value)) {
        factors.push_back(value);
        return;
    }
    const uint64_t divisor = pollard_rho(value);
    factor_recursively(divisor, factors);
    factor_recursively(value / divisor, factors);
}

}  // namespace internal

inline std::vector<uint64_t> prime_factors(uint64_t value) {
    assert(value >= 1);
    std::vector<uint64_t> result;
    internal::factor_recursively(value, result);
    std::sort(result.begin(), result.end());
    return result;
}

inline std::vector<std::pair<uint64_t, int>> prime_factorize(uint64_t value) {
    std::vector<uint64_t> factors = prime_factors(value);
    std::vector<std::pair<uint64_t, int>> result;
    for (uint64_t prime : factors) {
        if (result.empty() || result.back().first != prime) {
            result.emplace_back(prime, 1);
        } else {
            result.back().second++;
        }
    }
    return result;
}

inline std::vector<uint64_t> divisors(uint64_t value) {
    std::vector<uint64_t> result = {1};
    for (const auto& factor : prime_factorize(value)) {
        const int current_size = int(result.size());
        uint64_t power = 1;
        for (int exponent = 1; exponent <= factor.second; exponent++) {
            power *= factor.first;
            for (int i = 0; i < current_size; i++) {
                result.push_back(result[i] * power);
            }
        }
    }
    std::sort(result.begin(), result.end());
    return result;
}

inline uint64_t euler_phi(uint64_t value) {
    assert(value >= 1);
    uint64_t result = value;
    for (const auto& factor : prime_factorize(value)) {
        result = result / factor.first * (factor.first - 1);
    }
    return result;
}

inline int mobius(uint64_t value) {
    assert(value >= 1);
    int result = 1;
    for (const auto& factor : prime_factorize(value)) {
        if (factor.second >= 2) return 0;
        result = -result;
    }
    return result;
}

}  // namespace math
}  // namespace m1une


#line 11 "math/cyclotomic_polynomial.hpp"

namespace m1une {
namespace math {

template <class T = long long>
std::vector<T> cyclotomic_polynomial(std::uint64_t index) {
    assert(index >= 1);
    if (index == 1) return {T(-1), T(1)};

    const std::vector<std::pair<std::uint64_t, int>> factors =
        prime_factorize(index);
    std::uint64_t degree = index;
    for (const auto& factor : factors) {
        degree = degree / factor.first * (factor.first - 1);
    }
    assert(degree < std::numeric_limits<std::size_t>::max());

    std::vector<T> result(static_cast<std::size_t>(degree) + 1, T(0));
    result[0] = T(1);

    const std::size_t subset_count = std::size_t(1) << factors.size();
    for (std::size_t mask = 0; mask < subset_count; mask++) {
        std::uint64_t exponent = index;
        bool negative_mobius = false;
        for (std::size_t i = 0; i < factors.size(); i++) {
            if ((mask >> i) & 1) {
                exponent /= factors[i].first;
                negative_mobius = !negative_mobius;
            }
        }
        if (exponent > degree) continue;

        const std::size_t shift = static_cast<std::size_t>(exponent);
        if (negative_mobius) {
            // Divide by 1 - x^shift as a truncated formal power series.
            for (std::size_t i = shift; i <= degree; i++) {
                result[i] += result[i - shift];
            }
        } else {
            // Multiply by 1 - x^shift.
            for (std::size_t i = static_cast<std::size_t>(degree);
                 i >= shift;
                 i--) {
                result[i] -= result[i - shift];
                if (i == shift) break;
            }
        }
    }
    return result;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/discrete_logarithm.hpp"



#line 5 "math/discrete_logarithm.hpp"
#include <cmath>
#line 10 "math/discrete_logarithm.hpp"
#include <unordered_map>

namespace m1une {
namespace math {

namespace internal {

inline uint64_t discrete_logarithm_multiply(
    uint64_t first,
    uint64_t second,
    uint64_t mod
) {
    return static_cast<uint64_t>(static_cast<unsigned __int128>(first) * second % mod);
}

inline uint64_t discrete_logarithm_power(
    uint64_t base,
    uint64_t exponent,
    uint64_t mod
) {
    uint64_t result = 1 % mod;
    base %= mod;
    while (exponent > 0) {
        if (exponent & 1) result = discrete_logarithm_multiply(result, base, mod);
        base = discrete_logarithm_multiply(base, base, mod);
        exponent >>= 1;
    }
    return result;
}

inline uint64_t discrete_logarithm_ceil_sqrt(uint64_t value) {
    uint64_t result = static_cast<uint64_t>(std::sqrt(static_cast<long double>(value)));
    while (static_cast<unsigned __int128>(result) * result < value) result++;
    while (result > 0 &&
           static_cast<unsigned __int128>(result - 1) * (result - 1) >= value) {
        result--;
    }
    return result;
}

struct DiscreteLogarithmHash {
    std::size_t operator()(uint64_t value) const {
        value += 0x9e3779b97f4a7c15ULL;
        value = (value ^ (value >> 30)) * 0xbf58476d1ce4e5b9ULL;
        value = (value ^ (value >> 27)) * 0x94d049bb133111ebULL;
        value ^= value >> 31;
        return static_cast<std::size_t>(value);
    }
};

// Solves coefficient * base^exponent = target (mod mod) for a positive
// exponent. Both coefficient and base must be invertible modulo mod.
inline std::optional<uint64_t> discrete_logarithm_coprime(
    uint64_t coefficient,
    uint64_t base,
    uint64_t target,
    uint64_t mod
) {
    const uint64_t step = discrete_logarithm_ceil_sqrt(mod);
    std::unordered_map<uint64_t, uint64_t, DiscreteLogarithmHash> baby;
    baby.max_load_factor(0.7F);
    baby.reserve(static_cast<std::size_t>(step));

    uint64_t value = target;
    for (uint64_t exponent = 0; exponent < step; exponent++) {
        baby[value] = exponent;
        value = discrete_logarithm_multiply(value, base, mod);
    }

    const uint64_t giant_factor = discrete_logarithm_power(base, step, mod);
    uint64_t giant = coefficient;
    for (uint64_t block = 1; block <= step; block++) {
        giant = discrete_logarithm_multiply(giant, giant_factor, mod);
        auto it = baby.find(giant);
        if (it == baby.end()) continue;
        const unsigned __int128 candidate =
            static_cast<unsigned __int128>(block) * step - it->second;
        if (candidate <= UINT64_MAX) return static_cast<uint64_t>(candidate);
    }
    return std::nullopt;
}

}  // namespace internal

// Returns the smallest nonnegative exponent x satisfying base^x = target
// modulo mod, or nullopt when no such exponent exists. Defines 0^0 as 1.
inline std::optional<uint64_t> discrete_logarithm(
    uint64_t base,
    uint64_t target,
    uint64_t mod
) {
    assert(mod >= 1);
    if (mod == 1) return uint64_t(0);
    base %= mod;
    target %= mod;

    uint64_t coefficient = 1;
    uint64_t offset = 0;
    while (true) {
        if (coefficient == target) return offset;
        const uint64_t divisor = std::gcd(base, mod);
        if (divisor == 1) break;
        if (target % divisor != 0) return std::nullopt;
        target /= divisor;
        mod /= divisor;
        coefficient = internal::discrete_logarithm_multiply(
            coefficient % mod, (base / divisor) % mod, mod);
        offset++;
    }

    auto remaining = internal::discrete_logarithm_coprime(
        coefficient, base % mod, target, mod);
    if (!remaining.has_value()) return std::nullopt;
    return offset + *remaining;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/divisor_convolution.hpp"



#line 6 "math/divisor_convolution.hpp"

#line 8 "math/divisor_convolution.hpp"

namespace m1une {
namespace math {

template <typename T>
std::vector<T> gcd_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    if (first.empty() || second.empty()) return {};
    const std::size_t size = first.size() > second.size()
        ? first.size()
        : second.size();
    first.resize(size);
    second.resize(size);
    first[0] = T{};
    second[0] = T{};

    multiple_zeta_transform(first);
    multiple_zeta_transform(second);
    for (std::size_t index = 1; index < size; ++index) {
        first[index] *= second[index];
    }
    multiple_mobius_transform(first);
    return first;
}

template <typename T>
std::vector<T> lcm_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    if (first.empty() || second.empty()) return {};
    const std::size_t size = first.size() > second.size()
        ? first.size()
        : second.size();
    first.resize(size);
    second.resize(size);
    first[0] = T{};
    second[0] = T{};

    divisor_zeta_transform(first);
    divisor_zeta_transform(second);
    for (std::size_t index = 1; index < size; ++index) {
        first[index] *= second[index];
    }
    divisor_mobius_transform(first);
    return first;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/gaussian_integer.hpp"



#line 10 "math/gaussian_integer.hpp"

namespace m1une {
namespace math {

template <std::signed_integral T = long long>
struct GaussianInteger {
    static_assert(sizeof(T) <= sizeof(long long));

    using value_type = T;
    using norm_type = __uint128_t;

    T real;
    T imag;

   private:
    using wide_type = __int128_t;

    struct SignedMagnitude {
        norm_type magnitude;
        bool negative;
    };

    static constexpr norm_type magnitude(T value) {
        const wide_type wide = value;
        if (wide < 0) {
            return static_cast<norm_type>(-(wide + 1)) + 1;
        }
        return static_cast<norm_type>(wide);
    }

    static constexpr SignedMagnitude signed_value(T value) {
        return SignedMagnitude{magnitude(value), value < 0};
    }

    static constexpr SignedMagnitude negate(SignedMagnitude value) {
        if (value.magnitude != 0) value.negative = !value.negative;
        return value;
    }

    static constexpr SignedMagnitude add_signed(
        SignedMagnitude first,
        SignedMagnitude second
    ) {
        if (first.negative == second.negative) {
            return SignedMagnitude{
                first.magnitude + second.magnitude,
                first.negative
            };
        }
        if (first.magnitude < second.magnitude) {
            return SignedMagnitude{
                second.magnitude - first.magnitude,
                second.negative
            };
        }
        return SignedMagnitude{
            first.magnitude - second.magnitude,
            first.magnitude == second.magnitude ? false : first.negative
        };
    }

    static constexpr SignedMagnitude product(T first, T second) {
        const norm_type result = magnitude(first) * magnitude(second);
        return SignedMagnitude{
            result,
            result != 0 && ((first < 0) != (second < 0))
        };
    }

    static constexpr T narrow(SignedMagnitude value) {
        const norm_type maximum =
            static_cast<norm_type>(std::numeric_limits<T>::max());
        if (!value.negative) {
            assert(value.magnitude <= maximum);
            return static_cast<T>(value.magnitude);
        }

        assert(value.magnitude <= maximum + 1);
        if (value.magnitude == maximum + 1) {
            return std::numeric_limits<T>::min();
        }
        return static_cast<T>(-static_cast<wide_type>(value.magnitude));
    }

    static constexpr std::pair<SignedMagnitude, SignedMagnitude>
    product_components(
        const GaussianInteger& first,
        const GaussianInteger& second
    ) {
        const SignedMagnitude product_real = add_signed(
            product(first.real, second.real),
            negate(product(first.imag, second.imag))
        );
        const SignedMagnitude product_imag = add_signed(
            product(first.real, second.imag),
            product(first.imag, second.real)
        );
        return {product_real, product_imag};
    }

    static constexpr T round_ratio(
        SignedMagnitude numerator,
        norm_type denominator
    ) {
        assert(denominator != 0);
        norm_type quotient = numerator.magnitude / denominator;
        const norm_type remainder = numerator.magnitude % denominator;
        if (remainder + remainder >= denominator) quotient++;
        return narrow(SignedMagnitude{quotient, numerator.negative});
    }

   public:
    constexpr GaussianInteger() : real(0), imag(0) {}

    constexpr GaussianInteger(T real_) : real(real_), imag(0) {}

    constexpr GaussianInteger(T real_, T imag_)
        : real(real_), imag(imag_) {}

    constexpr bool is_zero() const {
        return real == 0 && imag == 0;
    }

    constexpr bool is_unit() const {
        return norm() == 1;
    }

    constexpr norm_type norm() const {
        const norm_type real_magnitude = magnitude(real);
        const norm_type imag_magnitude = magnitude(imag);
        return real_magnitude * real_magnitude +
               imag_magnitude * imag_magnitude;
    }

    constexpr GaussianInteger conjugate() const {
        return GaussianInteger(real, narrow(negate(signed_value(imag))));
    }

    constexpr GaussianInteger normalizing_unit() const {
        if (is_zero() || (0 < real && 0 <= imag)) {
            return GaussianInteger(1, 0);
        }
        if (0 < real) return GaussianInteger(0, 1);
        if (real < 0 && imag <= 0) return GaussianInteger(-1, 0);
        if (real < 0) return GaussianInteger(0, -1);
        if (0 < imag) return GaussianInteger(0, -1);
        return GaussianInteger(0, 1);
    }

    constexpr GaussianInteger normalized() const {
        return normalizing_unit() * *this;
    }

    constexpr std::pair<GaussianInteger, GaussianInteger> divmod(
        const GaussianInteger& divisor
    ) const {
        const norm_type divisor_norm = divisor.norm();
        assert(divisor_norm != 0);

        const SignedMagnitude numerator_real = add_signed(
            product(real, divisor.real),
            product(imag, divisor.imag)
        );
        const SignedMagnitude numerator_imag = add_signed(
            product(imag, divisor.real),
            negate(product(real, divisor.imag))
        );
        const GaussianInteger quotient(
            round_ratio(numerator_real, divisor_norm),
            round_ratio(numerator_imag, divisor_norm)
        );

        const auto product = product_components(quotient, divisor);
        const GaussianInteger remainder(
            narrow(add_signed(signed_value(real), negate(product.first))),
            narrow(add_signed(signed_value(imag), negate(product.second)))
        );
        assert(remainder.norm() < divisor_norm);
        return {quotient, remainder};
    }

    constexpr GaussianInteger operator+() const {
        return *this;
    }

    constexpr GaussianInteger operator-() const {
        return GaussianInteger(
            narrow(negate(signed_value(real))),
            narrow(negate(signed_value(imag)))
        );
    }

    constexpr GaussianInteger& operator+=(const GaussianInteger& other) {
        real = narrow(add_signed(signed_value(real), signed_value(other.real)));
        imag = narrow(add_signed(signed_value(imag), signed_value(other.imag)));
        return *this;
    }

    constexpr GaussianInteger& operator-=(const GaussianInteger& other) {
        real = narrow(add_signed(
            signed_value(real),
            negate(signed_value(other.real))
        ));
        imag = narrow(add_signed(
            signed_value(imag),
            negate(signed_value(other.imag))
        ));
        return *this;
    }

    constexpr GaussianInteger& operator*=(const GaussianInteger& other) {
        const auto result = product_components(*this, other);
        real = narrow(result.first);
        imag = narrow(result.second);
        return *this;
    }

    constexpr GaussianInteger& operator/=(const GaussianInteger& other) {
        *this = divmod(other).first;
        return *this;
    }

    constexpr GaussianInteger& operator%=(const GaussianInteger& other) {
        *this = divmod(other).second;
        return *this;
    }

    friend constexpr GaussianInteger operator+(
        GaussianInteger left,
        const GaussianInteger& right
    ) {
        return left += right;
    }

    friend constexpr GaussianInteger operator-(
        GaussianInteger left,
        const GaussianInteger& right
    ) {
        return left -= right;
    }

    friend constexpr GaussianInteger operator*(
        GaussianInteger left,
        const GaussianInteger& right
    ) {
        return left *= right;
    }

    friend constexpr GaussianInteger operator/(
        GaussianInteger left,
        const GaussianInteger& right
    ) {
        return left /= right;
    }

    friend constexpr GaussianInteger operator%(
        GaussianInteger left,
        const GaussianInteger& right
    ) {
        return left %= right;
    }

    friend constexpr bool operator==(
        const GaussianInteger& first,
        const GaussianInteger& second
    ) = default;
};

template <std::signed_integral T>
constexpr bool gaussian_divides(
    const GaussianInteger<T>& divisor,
    const GaussianInteger<T>& value
) {
    if (divisor.is_zero()) return value.is_zero();
    return (value % divisor).is_zero();
}

template <std::signed_integral T>
constexpr bool gaussian_associates(
    const GaussianInteger<T>& first,
    const GaussianInteger<T>& second
) {
    return first.normalized() == second.normalized();
}

template <std::signed_integral T>
constexpr GaussianInteger<T> gaussian_gcd(
    GaussianInteger<T> first,
    GaussianInteger<T> second
) {
    while (!second.is_zero()) {
        first %= second;
        std::swap(first, second);
    }
    return first.normalized();
}

template <std::signed_integral T>
constexpr std::tuple<
    GaussianInteger<T>,
    GaussianInteger<T>,
    GaussianInteger<T>
> extended_gaussian_gcd(
    GaussianInteger<T> first,
    GaussianInteger<T> second
) {
    using G = GaussianInteger<T>;
    G old_remainder = first;
    G remainder = second;
    G old_first_coefficient(1);
    G first_coefficient(0);
    G old_second_coefficient(0);
    G second_coefficient(1);

    while (!remainder.is_zero()) {
        const G quotient = old_remainder / remainder;

        G next = old_remainder - quotient * remainder;
        old_remainder = remainder;
        remainder = next;

        next = old_first_coefficient - quotient * first_coefficient;
        old_first_coefficient = first_coefficient;
        first_coefficient = next;

        next = old_second_coefficient - quotient * second_coefficient;
        old_second_coefficient = second_coefficient;
        second_coefficient = next;
    }

    const G unit = old_remainder.normalizing_unit();
    return {
        unit * old_remainder,
        unit * old_first_coefficient,
        unit * old_second_coefficient
    };
}

}  // namespace math
}  // namespace m1une


#line 1 "math/generalized_floor_sum.hpp"



#line 9 "math/generalized_floor_sum.hpp"

namespace m1une {
namespace math {

template <class T, int MaxPower, int MaxFloorPower>
using GeneralizedFloorSumTable =
    std::array<std::array<T, MaxFloorPower + 1>, MaxPower + 1>;

namespace generalized_floor_sum_detail {

using SignedWide = __int128_t;
using UnsignedWide = __uint128_t;

template <class T>
T from_wide(SignedWide value) {
    bool negative = value < 0;
    UnsignedWide magnitude;
    if (negative) {
        magnitude = static_cast<UnsignedWide>(-(value + 1));
        ++magnitude;
    } else {
        magnitude = static_cast<UnsignedWide>(value);
    }

    T result = T();
    T binary_place = T(1);
    while (magnitude > 0) {
        if ((magnitude & 1) != 0) result += binary_place;
        magnitude >>= 1;
        if (magnitude > 0) binary_place += binary_place;
    }
    return negative ? T() - result : result;
}

inline SignedWide floor_div(SignedWide numerator, SignedWide denominator) {
    assert(denominator > 0);
    SignedWide quotient = numerator / denominator;
    if (numerator % denominator < 0) --quotient;
    return quotient;
}

template <class T, int MaxPower, int MaxFloorPower>
class MomentMonoid {
   public:
    using Table = GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower>;

    struct Data {
        Table sums{};
        T delta_x = T();
        T delta_y = T();
    };

    static constexpr int MaximumDegree =
        MaxPower > MaxFloorPower ? MaxPower : MaxFloorPower;

    MomentMonoid() {
        binomial_[0][0] = T(1);
        for (int degree = 0; degree < MaximumDegree; ++degree) {
            for (int index = 0; index <= degree; ++index) {
                binomial_[degree + 1][index] += binomial_[degree][index];
                binomial_[degree + 1][index + 1] +=
                    binomial_[degree][index];
            }
        }
    }

    const T& binomial(int n, int k) const {
        assert(0 <= k && k <= n && n <= MaximumDegree);
        return binomial_[n][k];
    }

    Data unit() const {
        return Data();
    }

    Data x_step() const {
        Data result;
        result.sums[0][0] = T(1);
        result.delta_x = T(1);
        return result;
    }

    Data y_step() const {
        Data result;
        result.delta_y = T(1);
        return result;
    }

    Data concatenate(Data left, Data right) const {
        std::array<T, MaxPower + 1> x_powers{};
        std::array<T, MaxFloorPower + 1> y_powers{};
        x_powers[0] = T(1);
        y_powers[0] = T(1);
        for (int power = 0; power < MaxPower; ++power) {
            x_powers[power + 1] = x_powers[power] * left.delta_x;
        }
        for (int power = 0; power < MaxFloorPower; ++power) {
            y_powers[power + 1] = y_powers[power] * left.delta_y;
        }

        // Shift the y-coordinate of every sampled x-step in the right path.
        for (int x_power = 0; x_power <= MaxPower; ++x_power) {
            for (int old_power = MaxFloorPower; old_power >= 0; --old_power) {
                T source = right.sums[x_power][old_power];
                for (int new_power = old_power + 1;
                     new_power <= MaxFloorPower;
                     ++new_power) {
                    right.sums[x_power][new_power] +=
                        binomial_[new_power][old_power] *
                        y_powers[new_power - old_power] * source;
                }
            }
        }

        // Shift x, then append all samples from the right path.
        for (int y_power = 0; y_power <= MaxFloorPower; ++y_power) {
            for (int old_power = 0; old_power <= MaxPower; ++old_power) {
                T source = right.sums[old_power][y_power];
                for (int new_power = old_power;
                     new_power <= MaxPower;
                     ++new_power) {
                    left.sums[new_power][y_power] +=
                        binomial_[new_power][old_power] *
                        x_powers[new_power - old_power] * source;
                }
            }
        }

        left.delta_x += right.delta_x;
        left.delta_y += right.delta_y;
        return left;
    }

   private:
    std::array<std::array<T, MaximumDegree + 1>, MaximumDegree + 1>
        binomial_{};
};

template <class Monoid>
typename Monoid::Data monoid_power(
    const Monoid& monoid,
    typename Monoid::Data base,
    UnsignedWide exponent
) {
    typename Monoid::Data result = monoid.unit();
    while (exponent > 0) {
        if ((exponent & 1) != 0) {
            result = monoid.concatenate(std::move(result), base);
        }
        exponent >>= 1;
        if (exponent > 0) {
            base = monoid.concatenate(base, base);
        }
    }
    return result;
}

template <class Monoid>
typename Monoid::Data floor_path_product(
    const Monoid& monoid,
    UnsignedWide n,
    UnsignedWide a,
    UnsignedWide b,
    UnsignedWide modulus
) {
    assert(modulus > 0);
    UnsignedWide height = (a * n + b) / modulus;
    typename Monoid::Data x = monoid.x_step();
    typename Monoid::Data y = monoid.y_step();
    typename Monoid::Data prefix = monoid.unit();
    typename Monoid::Data suffix = monoid.unit();

    while (true) {
        UnsignedWide slope_quotient = a / modulus;
        UnsignedWide intercept_quotient = b / modulus;
        a %= modulus;
        b %= modulus;

        x = monoid.concatenate(
            std::move(x),
            monoid_power(monoid, y, slope_quotient)
        );
        prefix = monoid.concatenate(
            std::move(prefix),
            monoid_power(monoid, y, intercept_quotient)
        );
        height -= slope_quotient * n + intercept_quotient;
        if (height == 0) break;

        assert(a > 0);
        UnsignedWide boundary =
            (modulus * height - b - 1) / a + 1;
        suffix = monoid.concatenate(
            y,
            monoid.concatenate(
                monoid_power(monoid, x, n - boundary),
                std::move(suffix)
            )
        );
        b = modulus - b - 1 + a;
        n = height - 1;
        height = boundary;
        std::swap(modulus, a);
        std::swap(x, y);
    }

    x = monoid_power(monoid, x, n);
    return monoid.concatenate(
        monoid.concatenate(std::move(prefix), std::move(x)),
        std::move(suffix)
    );
}

template <class T, int MaxPower, int MaxFloorPower>
GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower>
nonnegative_slope_table(
    const MomentMonoid<T, MaxPower, MaxFloorPower>& monoid,
    SignedWide n,
    SignedWide modulus,
    SignedWide a,
    SignedWide b
) {
    assert(n >= 0 && modulus > 0 && a >= 0);
    SignedWide y_offset = floor_div(b, modulus);
    SignedWide normalized_b = b - y_offset * modulus;

    auto path = floor_path_product(
        monoid,
        static_cast<UnsignedWide>(n),
        static_cast<UnsignedWide>(a),
        static_cast<UnsignedWide>(normalized_b),
        static_cast<UnsignedWide>(modulus)
    );

    std::array<T, MaxFloorPower + 1> offset_powers{};
    offset_powers[0] = T(1);
    T offset = from_wide<T>(y_offset);
    for (int power = 0; power < MaxFloorPower; ++power) {
        offset_powers[power + 1] = offset_powers[power] * offset;
    }

    GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower> result{};
    for (int x_power = 0; x_power <= MaxPower; ++x_power) {
        for (int y_power = 0; y_power <= MaxFloorPower; ++y_power) {
            for (int inner_power = 0;
                 inner_power <= y_power;
                 ++inner_power) {
                result[x_power][y_power] +=
                    monoid.binomial(y_power, inner_power) *
                    offset_powers[y_power - inner_power] *
                    path.sums[x_power][inner_power];
            }
        }
    }
    return result;
}

}  // namespace generalized_floor_sum_detail

// Returns every sum of x^p * floor((a*x+b)/mod)^q for 0 <= x < n,
// 0 <= p <= MaxPower, and 0 <= q <= MaxFloorPower.
template <class T, int MaxPower, int MaxFloorPower, class I>
GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower>
generalized_floor_sum_table(I n, I mod, I a, I b) {
    static_assert(MaxPower >= 0 && MaxFloorPower >= 0);
    static_assert(
        std::is_integral_v<I> && std::is_signed_v<I> && sizeof(I) <= 8,
        "generalized_floor_sum_table requires signed integer arguments"
    );
    assert(n >= 0);
    assert(mod > 0);

    namespace detail = generalized_floor_sum_detail;
    using Monoid = detail::MomentMonoid<T, MaxPower, MaxFloorPower>;
    static const Monoid monoid;

    detail::SignedWide wide_n = n;
    detail::SignedWide wide_mod = mod;
    detail::SignedWide wide_a = a;
    detail::SignedWide wide_b = b;
    if (wide_n == 0) {
        return GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower>();
    }
    if (wide_a >= 0) {
        return detail::nonnegative_slope_table(
            monoid,
            wide_n,
            wide_mod,
            wide_a,
            wide_b
        );
    }

    // Substitute x = n - 1 - t to make the slope nonnegative.
    auto reflected = detail::nonnegative_slope_table(
        monoid,
        wide_n,
        wide_mod,
        -wide_a,
        wide_a * (wide_n - 1) + wide_b
    );
    std::array<T, MaxPower + 1> offset_powers{};
    offset_powers[0] = T(1);
    T offset = detail::from_wide<T>(wide_n - 1);
    for (int power = 0; power < MaxPower; ++power) {
        offset_powers[power + 1] = offset_powers[power] * offset;
    }

    GeneralizedFloorSumTable<T, MaxPower, MaxFloorPower> result{};
    for (int x_power = 0; x_power <= MaxPower; ++x_power) {
        for (int y_power = 0; y_power <= MaxFloorPower; ++y_power) {
            for (int inner_power = 0;
                 inner_power <= x_power;
                 ++inner_power) {
                T coefficient =
                    monoid.binomial(x_power, inner_power) *
                    offset_powers[x_power - inner_power];
                if ((inner_power & 1) != 0) coefficient = T() - coefficient;
                result[x_power][y_power] +=
                    coefficient * reflected[inner_power][y_power];
            }
        }
    }
    return result;
}

template <class T, int Power, int FloorPower, class I>
T generalized_floor_sum(I n, I mod, I a, I b) {
    return generalized_floor_sum_table<T, Power, FloorPower>(n, mod, a, b)
        [Power][FloorPower];
}

}  // namespace math
}  // namespace m1une


#line 1 "math/integer_arithmetic.hpp"



#line 9 "math/integer_arithmetic.hpp"

namespace m1une {
namespace math {

namespace integer_arithmetic_detail {

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
constexpr std::optional<T> checked_multiply(T first, T second) {
    constexpr T minimum = std::numeric_limits<T>::min();
    constexpr T maximum = std::numeric_limits<T>::max();

    if constexpr (std::unsigned_integral<T>) {
        if (second != 0 && maximum / second < first) return std::nullopt;
    } else {
        if (0 < first) {
            if (0 < second) {
                if (maximum / second < first) return std::nullopt;
            } else if (second < minimum / first) {
                return std::nullopt;
            }
        } else if (first < 0) {
            if (0 < second) {
                if (first < minimum / second) return std::nullopt;
            } else if (second < maximum / first) {
                return std::nullopt;
            }
        }
    }
    return T(first * second);
}

template <std::unsigned_integral T>
constexpr bool kth_power_leq(T base, unsigned exponent, T limit) {
    assert(exponent > 0);
    if (base <= 1) return base <= limit;

    const T multiplication_limit = limit / base;
    T product = 1;
    for (unsigned i = 0; i < exponent; i++) {
        if (product > multiplication_limit) return false;
        product *= base;
    }
    return true;
}

}  // namespace integer_arithmetic_detail

// Returns floor(sqrt(value)) exactly, without floating-point arithmetic.
template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
constexpr T isqrt(T value) {
    if constexpr (std::signed_integral<T>) assert(0 <= value);
    if (value <= 1) return value;

    T low = 1;
    T high = value / 2 + 1;
    while (low < high) {
        T middle = low + (high - low + 1) / 2;
        if (middle <= value / middle) {
            low = middle;
        } else {
            high = middle - 1;
        }
    }
    return low;
}

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
constexpr T floor_sqrt(T value) {
    return isqrt(value);
}

// Returns ceil(sqrt(value)) exactly, without floating-point arithmetic.
template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
constexpr T ceil_sqrt(T value) {
    T result = isqrt(value);
    if (result == 0) return 0;
    if (result != 0 && value / result == result && value % result == 0) {
        return result;
    }
    return result + 1;
}

// Returns floor(value^(1 / degree)) exactly, without floating-point arithmetic.
template <std::integral T, std::integral Degree>
requires(
    !std::same_as<std::remove_cv_t<T>, bool>
    && !std::same_as<std::remove_cv_t<Degree>, bool>
)
constexpr T floor_kth_root(T value, Degree degree) {
    if constexpr (std::signed_integral<T>) {
        assert(0 <= value);
        if (value < 0) return T();
    }
    assert(0 < degree);
    if (degree <= 0) return T();
    if (value <= 1 || degree == 1) return value;
    if (degree == 2) return isqrt(value);

    using U = std::make_unsigned_t<T>;
    using UDegree = std::make_unsigned_t<Degree>;
    constexpr int digits = std::numeric_limits<U>::digits;
    const UDegree unsigned_degree = static_cast<UDegree>(degree);
    if (unsigned_degree >= static_cast<UDegree>(digits)) return T(1);
    const unsigned exponent = static_cast<unsigned>(unsigned_degree);
    const U unsigned_value = static_cast<U>(value);

    int bit_width = 0;
    for (U remaining = unsigned_value; remaining != 0; remaining >>= 1) {
        bit_width++;
    }
    const int root_bits =
        (bit_width + static_cast<int>(exponent) - 1) /
        static_cast<int>(exponent);

    U low = 1;
    U high = U(1) << root_bits;
    while (high - low > 1) {
        const U middle = low + (high - low) / 2;
        if (
            integer_arithmetic_detail::kth_power_leq(
                middle, exponent, unsigned_value
            )
        ) {
            low = middle;
        } else {
            high = middle;
        }
    }
    return static_cast<T>(low);
}

// Returns base^exponent, or nullopt when the result does not fit in T.
template <std::integral T, std::unsigned_integral Exponent>
requires(
    !std::same_as<std::remove_cv_t<T>, bool>
    && !std::same_as<std::remove_cv_t<Exponent>, bool>
)
constexpr std::optional<T> checked_ipow(T base, Exponent exponent) {
    T result = 1;
    while (exponent != 0) {
        if (exponent & 1) {
            auto product =
                integer_arithmetic_detail::checked_multiply(result, base);
            if (!product.has_value()) return std::nullopt;
            result = *product;
        }
        exponent >>= 1;
        if (exponent != 0) {
            auto square =
                integer_arithmetic_detail::checked_multiply(base, base);
            if (!square.has_value()) return std::nullopt;
            base = *square;
        }
    }
    return result;
}

template <std::integral T, std::unsigned_integral Exponent>
requires(
    !std::same_as<std::remove_cv_t<T>, bool>
    && !std::same_as<std::remove_cv_t<Exponent>, bool>
)
constexpr std::optional<T> checked_integer_pow(T base, Exponent exponent) {
    return checked_ipow(base, exponent);
}

// Returns base^exponent. The result must be representable by T.
template <std::integral T, std::unsigned_integral Exponent>
requires(
    !std::same_as<std::remove_cv_t<T>, bool>
    && !std::same_as<std::remove_cv_t<Exponent>, bool>
)
constexpr T ipow(T base, Exponent exponent) {
    std::optional<T> result = checked_ipow(base, exponent);
    assert(result.has_value());
    return result.value_or(T());
}

template <std::integral T, std::unsigned_integral Exponent>
requires(
    !std::same_as<std::remove_cv_t<T>, bool>
    && !std::same_as<std::remove_cv_t<Exponent>, bool>
)
constexpr T integer_pow(T base, Exponent exponent) {
    return ipow(base, exponent);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/lucas.hpp"



#line 7 "math/lucas.hpp"

namespace m1une {
namespace math {

template <class Mint>
struct Lucas {
   private:
    std::vector<Mint> _factorial;
    std::vector<Mint> _inverse_factorial;

    Mint small_binom(uint32_t n, uint32_t k) const {
        if (k > n) return Mint(0);
        return _factorial[n] * _inverse_factorial[k] * _inverse_factorial[n - k];
    }

   public:
    Lucas() {
        const uint32_t prime = Mint::mod();
        assert(2 <= prime);
        _factorial.resize(prime);
        _inverse_factorial.resize(prime);
        _factorial[0] = Mint(1);
        for (uint32_t i = 1; i < prime; i++) {
            _factorial[i] = _factorial[i - 1] * Mint(i);
        }
        _inverse_factorial[prime - 1] = _factorial[prime - 1].inv();
        for (uint32_t i = prime - 1; i > 0; i--) {
            _inverse_factorial[i - 1] = _inverse_factorial[i] * Mint(i);
        }
    }

    uint32_t prime() const {
        return Mint::mod();
    }

    Mint binom(uint64_t n, uint64_t k) const {
        if (k > n) return Mint(0);
        const uint64_t modulus = Mint::mod();
        Mint result = Mint(1);
        while (n > 0 || k > 0) {
            uint32_t n_digit = uint32_t(n % modulus);
            uint32_t k_digit = uint32_t(k % modulus);
            if (k_digit > n_digit) return Mint(0);
            result *= small_binom(n_digit, k_digit);
            n /= modulus;
            k /= modulus;
        }
        return result;
    }

    Mint operator()(uint64_t n, uint64_t k) const {
        return binom(n, k);
    }
};

template <class Mint>
using LucasTheorem = Lucas<Mint>;

}  // namespace math
}  // namespace m1une


#line 1 "math/fps/all.hpp"



#line 1 "math/fps/composition.hpp"



#line 10 "math/fps/composition.hpp"

#line 12 "math/fps/composition.hpp"

namespace m1une {
namespace fps {

namespace internal {

template <class Mint>
using CompositionMatrix = std::vector<std::vector<Mint>>;

template <class Mint>
CompositionMatrix<Mint> composition_convolution_2d(const CompositionMatrix<Mint>& lhs,
                                                   const CompositionMatrix<Mint>& rhs) {
    const int lhs_height = int(lhs.size());
    const int rhs_height = int(rhs.size());
    const int lhs_width = int(lhs[0].size());
    const int rhs_width = int(rhs[0].size());
    const int height = lhs_height + rhs_height - 1;
    const int width = lhs_width + rhs_width - 1;

    std::vector<Mint> flattened_lhs(std::size_t(lhs_height) * width);
    std::vector<Mint> flattened_rhs(std::size_t(rhs_height) * width);
    for (int i = 0; i < lhs_height; i++) {
        std::copy(lhs[i].begin(), lhs[i].end(),
                  flattened_lhs.begin() + std::size_t(i) * width);
    }
    for (int i = 0; i < rhs_height; i++) {
        std::copy(rhs[i].begin(), rhs[i].end(),
                  flattened_rhs.begin() + std::size_t(i) * width);
    }

    std::vector<Mint> flattened_result = convolution(flattened_lhs, flattened_rhs);
    CompositionMatrix<Mint> result(height, std::vector<Mint>(width));
    for (int i = 0; i < height; i++) {
        std::copy_n(flattened_result.begin() + std::size_t(i) * width, width,
                    result[i].begin());
    }
    return result;
}

// result[i] = sum_j kernel[j] * values[i + j]
template <class Mint>
std::vector<Mint> composition_middle_product(const std::vector<Mint>& values,
                                             const std::vector<Mint>& kernel) {
    assert(values.size() >= kernel.size() && !kernel.empty());
    const int kernel_size = int(kernel.size());
    const int result_size = int(values.size()) - kernel_size + 1;
    if (std::min(kernel_size, result_size) <= 32) {
        std::vector<Mint> result(result_size);
        for (int i = 0; i < result_size; i++) {
            for (int j = 0; j < kernel_size; j++) result[i] += kernel[j] * values[i + j];
        }
        return result;
    }

    int transform_size = 1;
    while ((transform_size << 1) <= int(values.size()) * 2 - 1) transform_size <<= 1;
    if ((Mint::mod() - 1) % uint32_t(transform_size) == 0) {
        std::vector<Mint> transformed_values(transform_size);
        std::vector<Mint> transformed_kernel(transform_size);
        std::copy(values.begin(), values.end(), transformed_values.begin());
        std::reverse_copy(kernel.begin(), kernel.end(), transformed_kernel.begin());
        ntt(transformed_values, false);
        ntt(transformed_kernel, false);
        for (int i = 0; i < transform_size; i++) transformed_values[i] *= transformed_kernel[i];
        ntt(transformed_values, true);
        return std::vector<Mint>(transformed_values.begin() + kernel_size - 1,
                                 transformed_values.begin() + int(values.size()));
    }

    std::vector<Mint> reversed_kernel(kernel.rbegin(), kernel.rend());
    std::vector<Mint> product = convolution(values, reversed_kernel);
    return std::vector<Mint>(product.begin() + kernel_size - 1,
                             product.begin() + int(values.size()));
}

}  // namespace internal

// Returns outer(inner(x)) modulo x^degree. Formal composition requires inner(0) = 0.
template <class Mint>
FormalPowerSeries<Mint> compose(const FormalPowerSeries<Mint>& outer,
                                const FormalPowerSeries<Mint>& inner, int degree = -1) {
    using Matrix = internal::CompositionMatrix<Mint>;
    if (degree < 0) degree = int(outer.size());
    assert(degree >= 0);
    if (degree == 0) return {};
    assert(inner.empty() || inner[0] == Mint(0));

    FormalPowerSeries<Mint> coefficients = outer.pre(degree);
    FormalPowerSeries<Mint> argument = inner.pre(degree);

    auto transpose_power_projection = [&](auto&& self, Matrix denominator) -> Matrix {
        const int x_degree = int(denominator.size()) - 1;
        const int y_degree = int(denominator[0].size()) - 1;
        if (x_degree == 0) {
            Matrix result(1, std::vector<Mint>(y_degree + 1));
            std::copy(coefficients.begin(), coefficients.end(), result[0].begin());
            return result;
        }

        Matrix conjugate = denominator;
        for (int i = 1; i <= x_degree; i += 2) {
            for (Mint& value : conjugate[i]) value = Mint(0) - value;
        }
        Matrix reduced = internal::composition_convolution_2d(denominator, conjugate);
        for (int i = 1; i <= x_degree / 2; i++) reduced[i] = std::move(reduced[i << 1]);
        reduced.resize(x_degree / 2 + 1);
        Matrix().swap(denominator);

        Matrix projected = self(self, std::move(reduced));
        const int block_width = 2 * y_degree + 1;
        std::vector<Mint> expanded(std::size_t(2) * (x_degree + 1) * block_width - 1);
        for (int i = 0; i < int(projected.size()); i++) {
            for (int j = 0; j < int(projected[i].size()); j++) {
                const int row = 2 * i + (x_degree & 1);
                expanded[std::size_t(row) * block_width + j] = projected[i][j];
            }
        }

        std::vector<Mint> flattened_conjugate(std::size_t(x_degree + 1) * block_width);
        for (int i = 0; i <= x_degree; i++) {
            std::copy(conjugate[i].begin(), conjugate[i].end(),
                      flattened_conjugate.begin() + std::size_t(i) * block_width);
        }
        std::vector<Mint> middle =
            internal::composition_middle_product(expanded, flattened_conjugate);

        Matrix result(x_degree + 1, std::vector<Mint>(y_degree + 1));
        for (int i = 0; i <= x_degree; i++) {
            std::copy_n(middle.begin() + std::size_t(i) * block_width, y_degree + 1,
                        result[i].begin());
        }
        return result;
    };

    Matrix denominator(degree, std::vector<Mint>(2));
    denominator[0][0] = Mint(1);
    for (int i = 0; i < degree; i++) denominator[i][1] = Mint(0) - argument[i];
    Matrix transposed =
        transpose_power_projection(transpose_power_projection, std::move(denominator));

    FormalPowerSeries<Mint> result(degree);
    for (int i = 0; i < degree; i++) result[i] = transposed[i][0];
    std::reverse(result.begin(), result.end());
    return result;
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/compositional_inverse.hpp"



#line 6 "math/fps/compositional_inverse.hpp"

#line 8 "math/fps/compositional_inverse.hpp"

namespace m1une {
namespace fps {

template <class Mint>
FormalPowerSeries<Mint> compositional_inverse(const FormalPowerSeries<Mint>& f,
                                              int degree = -1) {
    using Fps = FormalPowerSeries<Mint>;
    if (degree < 0) degree = int(f.size());
    assert(degree >= 0);
    if (degree == 0) return {};
    assert(f.size() >= 2 && f[0] == Mint(0) && f[1] != Mint(0));

    Fps result(2);
    result[1] = f[1].inv();
    if (degree == 1) return result.pre(1);

    for (int size = 2; size < degree;) {
        const int next_size = std::min(size << 1, degree);
        Fps composed = compose(f.pre(next_size), result, next_size);
        const int correction_size = next_size - size;
        Fps inverse_derivative = composed.derivative().inv(correction_size);
        composed[1] -= Mint(1);
        Fps inverse_jacobian =
            (result.derivative().pre(correction_size) * inverse_derivative)
                .pre(correction_size);
        Fps correction = ((composed >> size) * inverse_jacobian).pre(correction_size);
        correction <<= size;

        result = result.pre(next_size) - correction;
        result.resize(next_size);
        size = next_size;
    }
    return result.pre(degree);
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/convolution_ll.hpp"



#line 8 "math/fps/convolution_ll.hpp"

#line 11 "math/fps/convolution_ll.hpp"

namespace m1une {
namespace fps {

// Exact convolution of signed 64-bit coefficients.
// Every result coefficient must fit in long long.
inline std::vector<long long> convolution_ll(
    const std::vector<long long>& first,
    const std::vector<long long>& second
) {
    if (first.empty() || second.empty()) return {};
    std::size_t result_size = first.size() + second.size() - 1;
    assert(result_size <= (std::size_t(1) << 24));

    using Mint1 = math::ModInt<167772161>;
    using Mint2 = math::ModInt<469762049>;
    using Mint3 = math::ModInt<754974721>;

    auto convolve = [&]<class Mint>() {
        std::vector<Mint> converted_first(first.size());
        std::vector<Mint> converted_second(second.size());
        for (int index = 0; index < int(first.size()); index++) {
            converted_first[index] = Mint(first[index]);
        }
        for (int index = 0; index < int(second.size()); index++) {
            converted_second[index] = Mint(second[index]);
        }
        return convolution(converted_first, converted_second);
    };

    std::vector<Mint1> result1 = convolve.template operator()<Mint1>();
    std::vector<Mint2> result2 = convolve.template operator()<Mint2>();
    std::vector<Mint3> result3 = convolve.template operator()<Mint3>();

    static const std::uint64_t inverse_mod1_mod2 =
        Mint2(Mint1::mod()).inv().val();
    static const std::uint64_t mod1_mod2 =
        std::uint64_t(Mint1::mod()) * Mint2::mod();
    static const std::uint64_t inverse_mod1_mod2_mod3 =
        Mint3(mod1_mod2 % Mint3::mod()).inv().val();
    static const unsigned __int128 crt_modulus =
        static_cast<unsigned __int128>(mod1_mod2) * Mint3::mod();

    std::vector<long long> result(result_size);
    for (int index = 0; index < int(result_size); index++) {
        std::uint64_t residue1 = result1[index].val();
        std::uint64_t residue2 = result2[index].val();
        std::uint64_t residue3 = result3[index].val();

        std::uint64_t second_digit =
            (residue2 + Mint2::mod() - residue1 % Mint2::mod()) %
            Mint2::mod();
        second_digit = second_digit * inverse_mod1_mod2 % Mint2::mod();
        std::uint64_t first_two =
            residue1 + std::uint64_t(Mint1::mod()) * second_digit;

        std::uint64_t third_digit =
            (residue3 + Mint3::mod() - first_two % Mint3::mod()) %
            Mint3::mod();
        third_digit =
            third_digit * inverse_mod1_mod2_mod3 % Mint3::mod();

        unsigned __int128 reconstructed =
            first_two + static_cast<unsigned __int128>(mod1_mod2) * third_digit;
        __int128 centered = reconstructed <= crt_modulus / 2
                                ? static_cast<__int128>(reconstructed)
                                : -static_cast<__int128>(crt_modulus - reconstructed);
        assert(std::numeric_limits<long long>::min() <= centered);
        assert(centered <= std::numeric_limits<long long>::max());
        result[index] = static_cast<long long>(centered);
    }
    return result;
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/floating_point_convolution.hpp"



#line 5 "math/fps/floating_point_convolution.hpp"
#include <bit>
#line 7 "math/fps/floating_point_convolution.hpp"
#include <complex>
#line 9 "math/fps/floating_point_convolution.hpp"
#include <numbers>
#line 12 "math/fps/floating_point_convolution.hpp"

namespace m1une {
namespace fps {

namespace floating_point_convolution_detail {

template <std::floating_point Real>
void fft(std::vector<std::complex<Real>>& values, bool inverse) {
    int size = int(values.size());
    for (int index = 1, reversed = 0; index < size; ++index) {
        int bit = size >> 1;
        while (reversed & bit) {
            reversed ^= bit;
            bit >>= 1;
        }
        reversed ^= bit;
        if (index < reversed) std::swap(values[index], values[reversed]);
    }

    for (int length = 2; length <= size; length <<= 1) {
        Real angle = Real(2) * std::numbers::pi_v<Real> / Real(length);
        if (inverse) angle = -angle;
        std::complex<Real> step(std::cos(angle), std::sin(angle));
        int half = length >> 1;
        for (int offset = 0; offset < size; offset += length) {
            std::complex<Real> root(1, 0);
            for (int index = 0; index < half; ++index) {
                std::complex<Real> even = values[offset + index];
                std::complex<Real> odd = values[offset + index + half] * root;
                values[offset + index] = even + odd;
                values[offset + index + half] = even - odd;
                root *= step;
            }
        }
    }

    if (inverse) {
        Real inverse_size = Real(1) / Real(size);
        for (auto& value : values) value *= inverse_size;
    }
}

template <std::floating_point Real>
std::vector<std::complex<Real>> complex_convolution(const std::vector<std::complex<Real>>& first,
                                                    const std::vector<std::complex<Real>>& second) {
    if (first.empty() || second.empty()) return {};
    std::size_t result_size = first.size() + second.size() - 1;
    std::size_t size = std::bit_ceil(result_size);
    std::vector<std::complex<Real>> transformed_first(size);
    std::vector<std::complex<Real>> transformed_second(size);
    std::copy(first.begin(), first.end(), transformed_first.begin());
    std::copy(second.begin(), second.end(), transformed_second.begin());

    fft(transformed_first, false);
    fft(transformed_second, false);
    for (std::size_t index = 0; index < size; ++index) {
        transformed_first[index] *= transformed_second[index];
    }
    fft(transformed_first, true);
    transformed_first.resize(result_size);
    return transformed_first;
}

}  // namespace floating_point_convolution_detail

// Convolution of complex floating-point coefficients.
template <std::floating_point Real>
std::vector<std::complex<Real>> convolution_fft(const std::vector<std::complex<Real>>& first,
                                                const std::vector<std::complex<Real>>& second) {
    return floating_point_convolution_detail::complex_convolution(first, second);
}

// Convolution of real floating-point coefficients.
template <std::floating_point Real>
std::vector<Real> convolution_fft(const std::vector<Real>& first, const std::vector<Real>& second) {
    if (first.empty() || second.empty()) return {};
    std::vector<std::complex<Real>> complex_first(first.size());
    std::vector<std::complex<Real>> complex_second(second.size());
    for (std::size_t index = 0; index < first.size(); ++index) {
        complex_first[index] = std::complex<Real>(first[index], 0);
    }
    for (std::size_t index = 0; index < second.size(); ++index) {
        complex_second[index] = std::complex<Real>(second[index], 0);
    }
    auto result = floating_point_convolution_detail::complex_convolution(complex_first, complex_second);
    std::vector<Real> real_result(result.size());
    for (std::size_t index = 0; index < result.size(); ++index) {
        real_result[index] = result[index].real();
    }
    return real_result;
}

// Uses long-double FFT and rounds each coefficient to the nearest integer.
template <std::integral Integer>
std::vector<Integer> convolution_round(const std::vector<Integer>& first, const std::vector<Integer>& second) {
    if (first.empty() || second.empty()) return {};
    std::vector<long double> real_first(first.begin(), first.end());
    std::vector<long double> real_second(second.begin(), second.end());
    std::vector<long double> real_result = convolution_fft(real_first, real_second);
    std::vector<Integer> result(real_result.size());
    for (std::size_t index = 0; index < result.size(); ++index) {
        result[index] = static_cast<Integer>(std::round(real_result[index]));
    }
    return result;
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/geometric_sequence_evaluation.hpp"



#line 8 "math/fps/geometric_sequence_evaluation.hpp"

#line 10 "math/fps/geometric_sequence_evaluation.hpp"

namespace m1une {
namespace fps {

namespace internal {

template <class Mint>
std::vector<Mint> geometric_triangular_powers(Mint ratio, int count) {
    assert(count >= 0);
    std::vector<Mint> result(count);
    if (count == 0) return result;
    result[0] = Mint(1);
    Mint power = Mint(1);
    for (int i = 0; i + 1 < count; ++i) {
        result[i + 1] = result[i] * power;
        power *= ratio;
    }
    return result;
}

template <class Mint>
std::vector<Mint> geometric_batch_inverse(const std::vector<Mint>& values) {
    const int count = int(values.size());
    std::vector<Mint> prefix(count + 1, Mint(1));
    for (int i = 0; i < count; ++i) {
        assert(values[i] != Mint(0));
        prefix[i + 1] = prefix[i] * values[i];
    }

    std::vector<Mint> result(count);
    Mint inverse_suffix = prefix[count].inv();
    for (int i = count - 1; i >= 0; --i) {
        result[i] = prefix[i] * inverse_suffix;
        inverse_suffix *= values[i];
    }
    return result;
}

template <class Mint>
std::vector<Mint> geometric_middle_product(const std::vector<Mint>& first,
                                           std::vector<Mint> second) {
    assert(first.size() >= second.size());
    if (second.empty()) return std::vector<Mint>(first.size() + 1);
    std::reverse(second.begin(), second.end());
    const std::vector<Mint> product = convolution(first, second);
    const int result_size = int(first.size() - second.size() + 1);
    return std::vector<Mint>(product.begin() + second.size() - 1,
                             product.begin() + second.size() - 1 + result_size);
}

}  // namespace internal

template <class Mint>
std::vector<Mint> multipoint_evaluate_geometric(
    const FormalPowerSeries<Mint>& polynomial, Mint initial, Mint ratio, int count) {
    assert(count >= 0);
    if (count == 0) return {};
    if (polynomial.empty()) return std::vector<Mint>(count);
    if (initial == Mint(0)) return std::vector<Mint>(count, polynomial[0]);
    if (ratio == Mint(0)) {
        std::vector<Mint> result(count, polynomial[0]);
        result[0] = polynomial.evaluate(initial);
        return result;
    }

    const int coefficient_count = int(polynomial.size());
    std::vector<Mint> scaled(polynomial.begin(), polynomial.end());
    Mint initial_power = Mint(1);
    for (Mint& coefficient : scaled) {
        coefficient *= initial_power;
        initial_power *= initial;
    }

    const std::vector<Mint> chirp = internal::geometric_triangular_powers(
        ratio, coefficient_count + count - 1);
    const std::vector<Mint> inverse_chirp = internal::geometric_triangular_powers(
        ratio.inv(), std::max(coefficient_count, count));
    for (int i = 0; i < coefficient_count; ++i) scaled[i] *= inverse_chirp[i];
    std::reverse(scaled.begin(), scaled.end());

    const std::vector<Mint> product = convolution(scaled, chirp);
    std::vector<Mint> result(count);
    for (int i = 0; i < count; ++i) {
        result[i] = product[coefficient_count - 1 + i] * inverse_chirp[i];
    }
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> polynomial_interpolate_geometric(
    const std::vector<Mint>& values, Mint initial, Mint ratio) {
    using Fps = FormalPowerSeries<Mint>;
    const int count = int(values.size());
    if (count == 0) return {};
    if (count == 1) return Fps(1, values[0]);
    assert(initial != Mint(0));
    assert(ratio != Mint(0));

    std::vector<Mint> ratio_power(2 * count - 1, Mint(1));
    std::vector<Mint> chirp(2 * count - 1, Mint(1));
    for (int i = 0; i + 1 < int(ratio_power.size()); ++i) {
        ratio_power[i + 1] = ratio_power[i] * ratio;
        chirp[i + 1] = chirp[i] * ratio_power[i];
    }
    const std::vector<Mint> inverse_chirp =
        internal::geometric_triangular_powers(ratio.inv(), count);

    std::vector<Mint> difference_product(count, Mint(1));
    for (int i = 1; i < count; ++i) {
        assert(ratio_power[i] != Mint(1));
        difference_product[i] =
            difference_product[i - 1] * (Mint(1) - ratio_power[i]);
    }
    const std::vector<Mint> inverse_difference =
        internal::geometric_batch_inverse(difference_product);
    const Mint complete_product =
        difference_product[count - 1] * (Mint(1) - ratio_power[count]);

    std::vector<Mint> weighted = values;
    for (int i = 0; i < count; ++i) {
        weighted[i] *= chirp[count - 1 - i] * inverse_chirp[count - 1] *
                       inverse_difference[i] * inverse_difference[count - 1 - i];
        if (i & 1) weighted[i] = Mint(0) - weighted[i];
        weighted[i] *= inverse_chirp[i];
    }

    std::vector<Mint> coefficients =
        internal::geometric_middle_product(chirp, weighted);
    for (int i = 0; i < count; ++i) coefficients[i] *= inverse_chirp[i];

    std::vector<Mint> product_polynomial(count);
    product_polynomial[0] = Mint(1);
    for (int i = 1; i < count; ++i) {
        product_polynomial[i] = chirp[i] * complete_product * inverse_difference[i] *
                                inverse_difference[count - i];
        if (i & 1) product_polynomial[i] = Mint(0) - product_polynomial[i];
    }
    coefficients = convolution(coefficients, product_polynomial);
    coefficients.resize(count);

    std::reverse(coefficients.begin(), coefficients.end());
    const Mint inverse_initial = initial.inv();
    Mint inverse_initial_power = Mint(1);
    for (Mint& coefficient : coefficients) {
        coefficient *= inverse_initial_power;
        inverse_initial_power *= inverse_initial;
    }
    return Fps(std::move(coefficients));
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/half_gcd.hpp"



#line 7 "math/fps/half_gcd.hpp"

#line 9 "math/fps/half_gcd.hpp"

namespace m1une {
namespace fps {

template <class Mint>
struct PolynomialMatrix2x2 {
    using Fps = FormalPowerSeries<Mint>;

    Fps a00;
    Fps a01;
    Fps a10;
    Fps a11;

    static PolynomialMatrix2x2 identity() {
        return PolynomialMatrix2x2{Fps(1, Mint(1)), Fps(), Fps(), Fps(1, Mint(1))};
    }

    std::pair<Fps, Fps> apply(const Fps& first, const Fps& second) const {
        Fps result_first = a00 * first + a01 * second;
        Fps result_second = a10 * first + a11 * second;
        result_first.shrink();
        result_second.shrink();
        return std::make_pair(std::move(result_first), std::move(result_second));
    }

    friend PolynomialMatrix2x2 operator*(const PolynomialMatrix2x2& lhs,
                                          const PolynomialMatrix2x2& rhs) {
        PolynomialMatrix2x2 result;
        result.a00 = lhs.a00 * rhs.a00 + lhs.a01 * rhs.a10;
        result.a01 = lhs.a00 * rhs.a01 + lhs.a01 * rhs.a11;
        result.a10 = lhs.a10 * rhs.a00 + lhs.a11 * rhs.a10;
        result.a11 = lhs.a10 * rhs.a01 + lhs.a11 * rhs.a11;
        result.a00.shrink();
        result.a01.shrink();
        result.a10.shrink();
        result.a11.shrink();
        return result;
    }
};

namespace internal {

template <class Mint>
void polynomial_euclidean_step(PolynomialMatrix2x2<Mint>& matrix,
                               std::pair<FormalPowerSeries<Mint>,
                                         FormalPowerSeries<Mint>>& values) {
    using Fps = FormalPowerSeries<Mint>;
    assert(!values.second.empty());

    auto division = values.first.divmod(values.second);
    Fps next_a10 = matrix.a00 - matrix.a10 * division.first;
    Fps next_a11 = matrix.a01 - matrix.a11 * division.first;
    next_a10.shrink();
    next_a11.shrink();

    matrix.a00 = std::move(matrix.a10);
    matrix.a01 = std::move(matrix.a11);
    matrix.a10 = std::move(next_a10);
    matrix.a11 = std::move(next_a11);
    values.first = std::move(values.second);
    values.second = std::move(division.second);
}

template <class Mint>
PolynomialMatrix2x2<Mint> half_gcd_impl(
    std::pair<FormalPowerSeries<Mint>, FormalPowerSeries<Mint>> values) {
    using Matrix = PolynomialMatrix2x2<Mint>;

    const int first_size = int(values.first.size());
    const int half_size = (first_size + 1) / 2;
    if (int(values.second.size()) <= half_size) return Matrix::identity();

    Matrix first_matrix =
        half_gcd_impl<Mint>(std::make_pair(values.first >> half_size, values.second >> half_size));
    values = first_matrix.apply(values.first, values.second);
    if (int(values.second.size()) <= half_size) return first_matrix;

    polynomial_euclidean_step(first_matrix, values);
    if (int(values.second.size()) <= half_size) return first_matrix;

    const int first_degree = int(values.first.size()) - 1;
    const int shift = 2 * half_size - first_degree;
    assert(shift >= 0);
    values.first >>= shift;
    values.second >>= shift;
    return half_gcd_impl<Mint>(std::move(values)) * first_matrix;
}

template <class Mint>
PolynomialMatrix2x2<Mint> polynomial_gcd_matrix(FormalPowerSeries<Mint> first,
                                                FormalPowerSeries<Mint> second) {
    using Matrix = PolynomialMatrix2x2<Mint>;
    first.shrink();
    second.shrink();

    if (first.size() < second.size()) {
        Matrix result = polynomial_gcd_matrix(std::move(second), std::move(first));
        std::swap(result.a00, result.a01);
        std::swap(result.a10, result.a11);
        return result;
    }

    std::pair<FormalPowerSeries<Mint>, FormalPowerSeries<Mint>> values(
        std::move(first), std::move(second));
    Matrix result = Matrix::identity();
    while (true) {
        Matrix block = half_gcd_impl<Mint>(values);
        values = block.apply(values.first, values.second);
        if (values.second.empty()) return block * result;

        polynomial_euclidean_step(block, values);
        if (values.second.empty()) return block * result;
        result = block * result;
    }
}

}  // namespace internal

template <class Mint>
PolynomialMatrix2x2<Mint> half_gcd(FormalPowerSeries<Mint> first,
                                   FormalPowerSeries<Mint> second) {
    first.shrink();
    second.shrink();
    assert(first.size() >= second.size());
    return internal::half_gcd_impl<Mint>(std::make_pair(std::move(first), std::move(second)));
}

template <class Mint>
struct PolynomialExtendedGcdResult {
    FormalPowerSeries<Mint> gcd;
    FormalPowerSeries<Mint> x;
    FormalPowerSeries<Mint> y;
};

template <class Mint>
PolynomialExtendedGcdResult<Mint> polynomial_extended_gcd(
    const FormalPowerSeries<Mint>& first, const FormalPowerSeries<Mint>& second) {
    PolynomialMatrix2x2<Mint> matrix = internal::polynomial_gcd_matrix(first, second);
    auto values = matrix.apply(first, second);

    if (!values.first.empty()) {
        const Mint inverse_leading = values.first.back().inv();
        values.first *= inverse_leading;
        matrix.a00 *= inverse_leading;
        matrix.a01 *= inverse_leading;
    }
    return PolynomialExtendedGcdResult<Mint>{std::move(values.first), std::move(matrix.a00),
                                             std::move(matrix.a01)};
}

template <class Mint>
FormalPowerSeries<Mint> polynomial_gcd(const FormalPowerSeries<Mint>& first,
                                       const FormalPowerSeries<Mint>& second) {
    return polynomial_extended_gcd(first, second).gcd;
}

template <class Mint>
std::optional<FormalPowerSeries<Mint>> polynomial_inv_mod(
    const FormalPowerSeries<Mint>& polynomial, FormalPowerSeries<Mint> modulus) {
    modulus.shrink();
    assert(!modulus.empty());
    auto result = polynomial_extended_gcd(polynomial, modulus);
    if (result.gcd.size() != 1) return std::nullopt;
    return result.x % modulus;
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/lagrange_inversion.hpp"



#line 7 "math/fps/lagrange_inversion.hpp"

#line 9 "math/fps/lagrange_inversion.hpp"

namespace m1une {
namespace fps {

template <class Mint>
Mint lagrange_inversion_coefficient(const FormalPowerSeries<Mint>& phi, int degree) {
    assert(1 <= degree && uint32_t(degree) < Mint::mod());
    assert(!phi.empty() && phi[0] != Mint(0));

    FormalPowerSeries<Mint> power = phi.pre(degree).pow(degree, degree);
    return power[degree - 1] / Mint(degree);
}

template <class Mint>
Mint lagrange_burmann_coefficient(const FormalPowerSeries<Mint>& phi,
                                  const FormalPowerSeries<Mint>& outer, int degree) {
    assert(0 <= degree && uint32_t(degree) < Mint::mod());
    if (degree == 0) return outer.empty() ? Mint(0) : outer[0];
    assert(!phi.empty() && phi[0] != Mint(0));

    FormalPowerSeries<Mint> power = phi.pre(degree).pow(degree, degree);
    Mint result = 0;
    int limit = std::min(degree, int(outer.size()) - 1);
    for (int i = 1; i <= limit; i++) {
        result += Mint(i) * outer[i] * power[degree - i];
    }
    return result / Mint(degree);
}

template <class Mint>
Mint compositional_inverse_coefficient(const FormalPowerSeries<Mint>& f, int degree) {
    assert(0 <= degree && uint32_t(degree) < Mint::mod());
    assert(2 <= int(f.size()) && f[0] == Mint(0) && f[1] != Mint(0));
    if (degree == 0) return Mint(0);

    FormalPowerSeries<Mint> divided(degree);
    for (int i = 0; i < degree && i + 1 < int(f.size()); i++) divided[i] = f[i + 1];
    FormalPowerSeries<Mint> phi = divided.inv(degree);
    return lagrange_inversion_coefficient(phi, degree);
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/linear_recurrence.hpp"



#line 9 "math/fps/linear_recurrence.hpp"

#line 11 "math/fps/linear_recurrence.hpp"

namespace m1une {
namespace fps {

// Returns a shortest linear recurrence satisfied by the observed sequence.
// The returned coefficients use
// a[n] = recurrence[0] * a[n - 1] + ... + recurrence[d - 1] * a[n - d].
template <class Mint>
std::vector<Mint> berlekamp_massey(const std::vector<Mint>& sequence) {
    std::vector<Mint> connection(1, Mint(1));
    std::vector<Mint> previous(1, Mint(1));
    int order = 0;
    int shift = 1;
    Mint previous_discrepancy = Mint(1);

    for (int index = 0; index < int(sequence.size()); index++) {
        Mint discrepancy = sequence[index];
        for (int i = 1; i <= order; i++) {
            discrepancy += connection[i] * sequence[index - i];
        }
        if (discrepancy == Mint(0)) {
            shift++;
            continue;
        }

        const Mint scale = discrepancy / previous_discrepancy;
        std::vector<Mint> old_connection = connection;
        if (connection.size() < previous.size() + std::size_t(shift)) {
            connection.resize(previous.size() + std::size_t(shift));
        }
        for (int i = 0; i < int(previous.size()); i++) {
            connection[i + shift] -= scale * previous[i];
        }

        if (2 * order <= index) {
            order = index + 1 - order;
            previous = std::move(old_connection);
            previous_discrepancy = discrepancy;
            shift = 1;
        } else {
            shift++;
        }
    }

    std::vector<Mint> recurrence(order);
    for (int i = 0; i < order; i++) recurrence[i] = Mint(0) - connection[i + 1];
    return recurrence;
}

template <class Mint>
Mint coefficient_of_rational(FormalPowerSeries<Mint> numerator,
                             FormalPowerSeries<Mint> denominator, uint64_t index) {
    using Fps = FormalPowerSeries<Mint>;
    assert(!denominator.empty() && denominator[0] != Mint(0));

    while (index > 0) {
        Fps denominator_negative = denominator;
        for (int i = 1; i < int(denominator_negative.size()); i += 2) {
            denominator_negative[i] = Mint(0) - denominator_negative[i];
        }

        Fps numerator_product = numerator * denominator_negative;
        Fps denominator_product = denominator * denominator_negative;
        Fps next_numerator;
        Fps next_denominator;
        next_numerator.reserve((numerator_product.size() + 1) / 2);
        next_denominator.reserve((denominator_product.size() + 1) / 2);
        for (int i = int(index & 1); i < int(numerator_product.size()); i += 2) {
            next_numerator.emplace_back(numerator_product[i]);
        }
        for (int i = 0; i < int(denominator_product.size()); i += 2) {
            next_denominator.emplace_back(denominator_product[i]);
        }
        numerator = std::move(next_numerator);
        denominator = std::move(next_denominator);
        index >>= 1;
    }
    return numerator.empty() ? Mint(0) : numerator[0] / denominator[0];
}

template <class Mint>
Mint linear_recurrence_kth(const std::vector<Mint>& initial,
                           const std::vector<Mint>& recurrence, uint64_t index) {
    using Fps = FormalPowerSeries<Mint>;
    assert(!initial.empty() && initial.size() == recurrence.size());
    if (index < initial.size()) return initial[index];

    const int order = int(recurrence.size());
    Fps denominator(order + 1);
    denominator[0] = 1;
    for (int i = 0; i < order; i++) denominator[i + 1] = Mint(0) - recurrence[i];
    Fps numerator = (Fps(initial) * denominator).pre(order);
    return coefficient_of_rational(std::move(numerator), std::move(denominator), index);
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/multipoint_evaluation.hpp"



#line 6 "math/fps/multipoint_evaluation.hpp"

#line 8 "math/fps/multipoint_evaluation.hpp"

namespace m1une {
namespace fps {

template <class Mint>
struct SubproductTree {
    using Fps = FormalPowerSeries<Mint>;

   private:
    int point_count_;
    int leaf_count_;
    std::vector<Mint> points_;
    std::vector<Fps> product_;

   public:
    explicit SubproductTree(const std::vector<Mint>& points)
        : point_count_(points.size()), leaf_count_(1), points_(points) {
        while (leaf_count_ < point_count_) leaf_count_ <<= 1;
        product_.resize(leaf_count_ << 1);
        for (int i = 0; i < leaf_count_; i++) {
            if (i < point_count_) {
                product_[leaf_count_ + i].resize(2);
                product_[leaf_count_ + i][0] = Mint(0) - points_[i];
                product_[leaf_count_ + i][1] = Mint(1);
            } else {
                product_[leaf_count_ + i].resize(1, Mint(1));
            }
        }
        for (int node = leaf_count_ - 1; node > 0; node--) {
            product_[node] = product_[node << 1] * product_[node << 1 | 1];
        }
    }

    int size() const {
        return point_count_;
    }

    const Fps& product() const {
        return product_[1];
    }

    std::vector<Mint> evaluate(const Fps& polynomial) const {
        std::vector<Mint> result(point_count_);
        if (point_count_ == 0) return result;

        std::vector<Fps> remainder(leaf_count_ << 1);
        remainder[1] = polynomial % product_[1];
        for (int node = 1; node < leaf_count_; node++) {
            remainder[node << 1] = remainder[node] % product_[node << 1];
            remainder[node << 1 | 1] = remainder[node] % product_[node << 1 | 1];
        }
        for (int i = 0; i < point_count_; i++) {
            const Fps& value = remainder[leaf_count_ + i];
            result[i] = value.empty() ? Mint(0) : value[0];
        }
        return result;
    }

    Fps interpolate(const std::vector<Mint>& values) const {
        assert(int(values.size()) == point_count_);
        if (point_count_ == 0) return {};

        std::vector<Mint> derivative_values = evaluate(product_[1].derivative());
        std::vector<Fps> polynomial(leaf_count_ << 1);
        for (int i = 0; i < leaf_count_; i++) {
            polynomial[leaf_count_ + i].resize(1);
            if (i < point_count_) {
                assert(derivative_values[i] != Mint(0));
                polynomial[leaf_count_ + i][0] = values[i] / derivative_values[i];
            }
        }
        for (int node = leaf_count_ - 1; node > 0; node--) {
            polynomial[node] = polynomial[node << 1] * product_[node << 1 | 1] +
                               polynomial[node << 1 | 1] * product_[node << 1];
        }
        polynomial[1].resize(point_count_);
        return polynomial[1];
    }
};

template <class Mint>
std::vector<Mint> multipoint_evaluate(const FormalPowerSeries<Mint>& polynomial,
                                      const std::vector<Mint>& points) {
    return SubproductTree<Mint>(points).evaluate(polynomial);
}

template <class Mint>
FormalPowerSeries<Mint> polynomial_interpolate(const std::vector<Mint>& points,
                                               const std::vector<Mint>& values) {
    return SubproductTree<Mint>(points).interpolate(values);
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/polynomial_factorization.hpp"



#line 9 "math/fps/polynomial_factorization.hpp"

#line 11 "math/fps/polynomial_factorization.hpp"

namespace m1une {
namespace fps {

template <class Mint>
struct PolynomialFactor {
    FormalPowerSeries<Mint> polynomial;
    int multiplicity;
};

template <class Mint>
struct PolynomialFactorization {
    Mint leading_coefficient;
    std::vector<PolynomialFactor<Mint>> factors;
};

namespace internal {

template <class Mint>
FormalPowerSeries<Mint> factorization_monic(FormalPowerSeries<Mint> polynomial) {
    polynomial.shrink();
    if (polynomial.empty()) return polynomial;
    polynomial /= polynomial.back();
    return polynomial;
}

template <class Mint>
FormalPowerSeries<Mint> factorization_multiply(
    const FormalPowerSeries<Mint>& first,
    const FormalPowerSeries<Mint>& second
) {
    if (first.empty() || second.empty()) return {};
    FormalPowerSeries<Mint> result(first.size() + second.size() - 1);
    for (int i = 0; i < int(first.size()); i++) {
        for (int j = 0; j < int(second.size()); j++) {
            result[i + j] += first[i] * second[j];
        }
    }
    result.shrink();
    return result;
}

template <class Mint>
std::pair<FormalPowerSeries<Mint>, FormalPowerSeries<Mint>> factorization_divmod(
    FormalPowerSeries<Mint> dividend,
    FormalPowerSeries<Mint> divisor
) {
    dividend.shrink();
    divisor.shrink();
    assert(!divisor.empty());
    if (dividend.size() < divisor.size()) return std::make_pair(FormalPowerSeries<Mint>(), dividend);

    FormalPowerSeries<Mint> quotient(dividend.size() - divisor.size() + 1);
    const Mint inverse_leading = divisor.back().inv();
    for (int i = int(dividend.size()) - 1; i >= int(divisor.size()) - 1; i--) {
        const Mint coefficient = dividend[i] * inverse_leading;
        const int shift = i - int(divisor.size()) + 1;
        quotient[shift] = coefficient;
        if (coefficient == Mint(0)) continue;
        for (int j = 0; j < int(divisor.size()); j++) {
            dividend[shift + j] -= coefficient * divisor[j];
        }
    }
    quotient.shrink();
    dividend.resize(divisor.size() - 1);
    dividend.shrink();
    return std::make_pair(std::move(quotient), std::move(dividend));
}

template <class Mint>
FormalPowerSeries<Mint> factorization_gcd(
    FormalPowerSeries<Mint> first,
    FormalPowerSeries<Mint> second
) {
    first.shrink();
    second.shrink();
    while (!second.empty()) {
        FormalPowerSeries<Mint> remainder =
            factorization_divmod(std::move(first), second).second;
        first = std::move(second);
        second = std::move(remainder);
    }
    return factorization_monic(std::move(first));
}

template <class Mint>
FormalPowerSeries<Mint> factorization_multiply_mod(
    const FormalPowerSeries<Mint>& first,
    const FormalPowerSeries<Mint>& second,
    const FormalPowerSeries<Mint>& modulus
) {
    return factorization_divmod(factorization_multiply(first, second), modulus).second;
}

template <class Mint>
FormalPowerSeries<Mint> factorization_power_mod(
    FormalPowerSeries<Mint> base,
    uint64_t exponent,
    const FormalPowerSeries<Mint>& modulus
) {
    FormalPowerSeries<Mint> result(1, Mint(1));
    result = factorization_divmod(std::move(result), modulus).second;
    base = factorization_divmod(std::move(base), modulus).second;
    while (exponent > 0) {
        if (exponent & 1) result = factorization_multiply_mod(result, base, modulus);
        exponent >>= 1;
        if (exponent > 0) base = factorization_multiply_mod(base, base, modulus);
    }
    return result;
}

struct PolynomialFactorizationRandom {
    uint64_t state;

    uint64_t operator()() {
        state ^= state << 7;
        state ^= state >> 9;
        return state;
    }
};

template <class Mint>
FormalPowerSeries<Mint> factorization_random_polynomial(
    int coefficient_count,
    PolynomialFactorizationRandom& random
) {
    FormalPowerSeries<Mint> result(coefficient_count);
    const uint64_t mod = Mint::mod();
    for (Mint& coefficient : result) coefficient = Mint(random() % mod);
    result.shrink();
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> equal_degree_separator_odd(
    const FormalPowerSeries<Mint>& random_polynomial,
    int factor_degree,
    const FormalPowerSeries<Mint>& modulus
) {
    FormalPowerSeries<Mint> power = factorization_power_mod(
        random_polynomial, (uint64_t(Mint::mod()) - 1) / 2, modulus);
    FormalPowerSeries<Mint> result(1, Mint(1));
    for (int i = 0; i < factor_degree; i++) {
        result = factorization_multiply_mod(result, power, modulus);
        if (i + 1 < factor_degree) {
            power = factorization_power_mod(power, Mint::mod(), modulus);
        }
    }
    if (result.empty()) result.resize(1);
    result[0] -= Mint(1);
    result.shrink();
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> equal_degree_separator_two(
    const FormalPowerSeries<Mint>& random_polynomial,
    int factor_degree,
    const FormalPowerSeries<Mint>& modulus
) {
    FormalPowerSeries<Mint> power =
        factorization_divmod(random_polynomial, modulus).second;
    FormalPowerSeries<Mint> result;
    for (int i = 0; i < factor_degree; i++) {
        result += power;
        result.shrink();
        if (i + 1 < factor_degree) {
            power = factorization_multiply_mod(power, power, modulus);
        }
    }
    return result;
}

template <class Mint>
std::vector<FormalPowerSeries<Mint>> equal_degree_factorization(
    FormalPowerSeries<Mint> polynomial,
    int factor_degree,
    PolynomialFactorizationRandom& random
) {
    using Fps = FormalPowerSeries<Mint>;
    polynomial = factorization_monic(std::move(polynomial));
    std::vector<Fps> queue(1, std::move(polynomial));
    std::vector<Fps> result;
    for (int head = 0; head < int(queue.size()); head++) {
        Fps current = factorization_monic(std::move(queue[head]));
        const int degree = int(current.size()) - 1;
        if (degree == factor_degree) {
            result.push_back(std::move(current));
            continue;
        }

        Fps divisor;
        do {
            Fps random_polynomial =
                factorization_random_polynomial<Mint>(degree, random);
            Fps separator = Mint::mod() == 2
                ? equal_degree_separator_two(random_polynomial, factor_degree, current)
                : equal_degree_separator_odd(random_polynomial, factor_degree, current);
            divisor = factorization_gcd(current, std::move(separator));
        } while (divisor.size() <= 1 || divisor.size() == current.size());

        Fps quotient = factorization_divmod(current, divisor).first;
        queue.push_back(std::move(divisor));
        queue.push_back(std::move(quotient));
    }
    return result;
}

}  // namespace internal

template <class Mint>
PolynomialFactorization<Mint> polynomial_factorize(
    FormalPowerSeries<Mint> polynomial,
    uint64_t seed = 88172645463325252ULL
) {
    using Fps = FormalPowerSeries<Mint>;
    polynomial.shrink();
    assert(!polynomial.empty());

    const Mint leading_coefficient = polynomial.back();
    polynomial /= leading_coefficient;
    std::vector<PolynomialFactor<Mint>> factors;
    if (polynomial.size() == 1) return {leading_coefficient, std::move(factors)};

    if (seed == 0) seed = 88172645463325252ULL;
    internal::PolynomialFactorizationRandom random{seed};
    const Fps x = Fps({Mint(0), Mint(1)});
    Fps frobenius = x;
    for (int degree = 1;
         polynomial.size() > 1 && 2 * degree <= int(polynomial.size()) - 1;
         degree++) {
        frobenius = internal::factorization_power_mod(
            std::move(frobenius), Mint::mod(), polynomial);
        Fps difference = frobenius - x;
        difference.shrink();
        Fps product = internal::factorization_gcd(polynomial, std::move(difference));
        if (product.size() <= 1) continue;

        std::vector<Fps> distinct = internal::equal_degree_factorization(
            std::move(product), degree, random);
        for (Fps& factor : distinct) {
            int multiplicity = 0;
            while (factor.size() <= polynomial.size()) {
                auto division = internal::factorization_divmod(polynomial, factor);
                if (!division.second.empty()) break;
                polynomial = std::move(division.first);
                multiplicity++;
            }
            assert(multiplicity > 0);
            factors.push_back({std::move(factor), multiplicity});
        }
    }
    if (polynomial.size() > 1) {
        factors.push_back({internal::factorization_monic(std::move(polynomial)), 1});
    }

    auto less = [](const PolynomialFactor<Mint>& first,
                   const PolynomialFactor<Mint>& second) {
        if (first.polynomial.size() != second.polynomial.size()) {
            return first.polynomial.size() < second.polynomial.size();
        }
        for (int i = int(first.polynomial.size()) - 1; i >= 0; i--) {
            if (first.polynomial[i].val() != second.polynomial[i].val()) {
                return first.polynomial[i].val() < second.polynomial[i].val();
            }
        }
        return false;
    };
    std::sort(factors.begin(), factors.end(), less);

    std::vector<PolynomialFactor<Mint>> merged;
    for (PolynomialFactor<Mint>& factor : factors) {
        if (!merged.empty() && merged.back().polynomial == factor.polynomial) {
            merged.back().multiplicity += factor.multiplicity;
        } else {
            merged.push_back(std::move(factor));
        }
    }
    return {leading_coefficient, std::move(merged)};
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/polynomial_roots.hpp"



#line 9 "math/fps/polynomial_roots.hpp"

#line 11 "math/fps/polynomial_roots.hpp"

namespace m1une {
namespace fps {

namespace internal {

struct PolynomialRootsRandom {
    uint64_t state;

    uint64_t operator()() {
        state ^= state << 7;
        state ^= state >> 9;
        return state;
    }
};

template <class Mint>
FormalPowerSeries<Mint> polynomial_roots_power_mod(
    FormalPowerSeries<Mint> base, uint64_t exponent,
    const FormalPowerSeries<Mint>& modulus) {
    using Fps = FormalPowerSeries<Mint>;
    Fps result(1, Mint(1));
    result %= modulus;
    base %= modulus;
    while (exponent > 0) {
        if (exponent & 1) result = (result * base) % modulus;
        exponent >>= 1;
        if (exponent > 0) base = (base * base) % modulus;
    }
    return result;
}

}  // namespace internal

template <class Mint>
std::vector<Mint> polynomial_roots(
    FormalPowerSeries<Mint> polynomial,
    uint64_t seed = 88172645463325252ULL) {
    using Fps = FormalPowerSeries<Mint>;
    polynomial.shrink();
    assert(!polynomial.empty());
    if (polynomial.size() == 1) return {};

    const uint64_t modulus = Mint::mod();
    if (modulus == 2) {
        std::vector<Mint> result;
        if (polynomial.evaluate(Mint(0)) == Mint(0)) result.push_back(Mint(0));
        if (polynomial.evaluate(Mint(1)) == Mint(0)) result.push_back(Mint(1));
        return result;
    }
    assert(modulus & 1);

    Fps x(2);
    x[1] = Mint(1);
    Fps frobenius = internal::polynomial_roots_power_mod(x, modulus, polynomial);
    frobenius -= x;
    frobenius.shrink();
    Fps linear_part = polynomial_gcd(polynomial, frobenius);
    if (linear_part.size() <= 1) return {};

    if (seed == 0) seed = 88172645463325252ULL;
    internal::PolynomialRootsRandom random{seed};
    std::vector<Mint> result;
    auto split = [&](auto&& self, Fps current) -> void {
        current.shrink();
        if (current.size() <= 1) return;
        if (current.size() == 2) {
            result.push_back((Mint(0) - current[0]) / current[1]);
            return;
        }

        Fps divisor;
        do {
            Fps shifted_x(2);
            shifted_x[0] = Mint(random() % modulus);
            shifted_x[1] = Mint(1);
            Fps separator = internal::polynomial_roots_power_mod(
                std::move(shifted_x), (modulus - 1) / 2, current);
            if (separator.empty()) separator.resize(1);
            separator[0] -= Mint(1);
            separator.shrink();
            divisor = polynomial_gcd(current, separator);
        } while (divisor.size() <= 1 || divisor.size() == current.size());

        auto division = current.divmod(divisor);
        assert(division.second.empty());
        self(self, std::move(divisor));
        self(self, std::move(division.first));
    };
    split(split, std::move(linear_part));

    std::sort(result.begin(), result.end(), [](Mint lhs, Mint rhs) {
        return lhs.val() < rhs.val();
    });
    result.erase(std::unique(result.begin(), result.end()), result.end());
    return result;
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/solve_fps_equation.hpp"



#line 6 "math/fps/solve_fps_equation.hpp"

#line 1 "math/newton_method.hpp"



#line 5 "math/newton_method.hpp"

#line 7 "math/newton_method.hpp"

namespace m1une {
namespace math {

namespace newton_method_detail {

template <class T>
struct DefaultQuotient {
    template <class Numerator, class Denominator>
    auto operator()(
        const Numerator& numerator,
        const Denominator& denominator
    ) const {
        return numerator / denominator;
    }
};

template <class Mint>
struct DefaultQuotient<fps::FormalPowerSeries<Mint>> {
    using Fps = fps::FormalPowerSeries<Mint>;

    int degree;

    Fps operator()(const Fps& numerator, const Fps& denominator) const {
        return (numerator.pre(degree) * denominator.inv(degree)).pre(degree);
    }
};

template <class T>
DefaultQuotient<T> make_default_quotient(const T&) {
    return {};
}

template <class Mint>
DefaultQuotient<fps::FormalPowerSeries<Mint>> make_default_quotient(
    const fps::FormalPowerSeries<Mint>& value
) {
    return {int(value.size())};
}

}  // namespace newton_method_detail

template <class T, class F, class Derivative, class Quotient>
T newton_method(
    T initial,
    F function,
    Derivative derivative,
    int iterations,
    Quotient quotient
) {
    assert(iterations >= 0);
    for (int iteration = 0; iteration < iterations; iteration++) {
        auto numerator = function(initial);
        auto denominator = derivative(initial);
        initial -= quotient(numerator, denominator);
    }
    return initial;
}

template <class T, class F, class Derivative>
T newton_method(
    T initial,
    F function,
    Derivative derivative,
    int iterations
) {
    auto quotient = newton_method_detail::make_default_quotient(initial);
    return newton_method(initial, function, derivative, iterations, quotient);
}

}  // namespace math
}  // namespace m1une


#line 8 "math/fps/solve_fps_equation.hpp"

namespace m1une {
namespace fps {

// Extends a solution modulo x^initial.size() to a solution modulo x^degree.
// Both callbacks receive the precision currently requested by Newton lifting.
template <class Mint, class Function, class Derivative>
FormalPowerSeries<Mint> solve_fps_equation(
    FormalPowerSeries<Mint> initial,
    int degree,
    Function function,
    Derivative derivative
) {
    using Fps = FormalPowerSeries<Mint>;
    assert(degree >= 0);
    if (degree == 0) return {};
    assert(!initial.empty());
    if (int(initial.size()) >= degree) return initial.pre(degree);

    while (int(initial.size()) < degree) {
        const int next_degree = std::min(int(initial.size()) << 1, degree);
        initial.resize(next_degree);

        auto truncated_function = [&](const Fps& value) {
            return function(value, next_degree).pre(next_degree);
        };
        auto truncated_derivative = [&](const Fps& value) {
            return derivative(value, next_degree).pre(next_degree);
        };
        initial = math::newton_method(
            initial, truncated_function, truncated_derivative, 1
        );
    }
    return initial;
}

// Starts Newton lifting from a solution modulo x.
template <class Mint, class Function, class Derivative>
FormalPowerSeries<Mint> solve_fps_equation(
    int degree,
    Mint constant_solution,
    Function function,
    Derivative derivative
) {
    assert(degree >= 0);
    if (degree == 0) return {};
    return solve_fps_equation(
        FormalPowerSeries<Mint>(1, constant_solution),
        degree,
        function,
        derivative
    );
}

}  // namespace fps
}  // namespace m1une


#line 1 "math/fps/sparse_formal_power_series.hpp"



#line 9 "math/fps/sparse_formal_power_series.hpp"

#line 11 "math/fps/sparse_formal_power_series.hpp"

namespace m1une {
namespace fps {

template <class Mint>
using SparseFormalPowerSeries = std::vector<std::pair<int, Mint>>;

namespace internal {

template <class Mint>
void assert_valid_sparse_fps(const SparseFormalPowerSeries<Mint>& terms, int degree) {
    int previous_degree = -1;
    for (const auto& [term_degree, coefficient] : terms) {
        assert(0 <= term_degree && previous_degree < term_degree && term_degree < degree);
        assert(coefficient != Mint(0));
        previous_degree = term_degree;
    }
}

template <class Mint>
std::vector<Mint> sparse_integer_inverses(int degree) {
    assert(degree >= 0 && uint32_t(degree) < Mint::mod());
    std::vector<Mint> inverse(degree);
    if (degree <= 1) return inverse;
    inverse[1] = Mint(1);
    for (int i = 2; i < degree; i++) {
        const uint32_t quotient = Mint::mod() / uint32_t(i);
        const uint32_t remainder = Mint::mod() % uint32_t(i);
        inverse[i] = Mint(0) - Mint(quotient) * inverse[remainder];
    }
    return inverse;
}

template <class Mint>
FormalPowerSeries<Mint> sparse_unit_pow(const SparseFormalPowerSeries<Mint>& terms,
                                        Mint exponent, int degree) {
    assert(degree > 0 && !terms.empty());
    assert(terms[0].first == 0 && terms[0].second == Mint(1));
    std::vector<Mint> inverse = sparse_integer_inverses<Mint>(degree);
    FormalPowerSeries<Mint> result(degree);
    result[0] = Mint(1);
    for (int n = 1; n < degree; n++) {
        Mint coefficient = 0;
        for (int i = 1; i < int(terms.size()) && terms[i].first <= n; i++) {
            const auto& [d, value] = terms[i];
            coefficient += value * result[n - d] *
                           (exponent * Mint(d) - Mint(n - d));
        }
        result[n] = coefficient * inverse[n];
    }
    return result;
}

}  // namespace internal

template <class Mint>
FormalPowerSeries<Mint> sparse_fps_inv(const SparseFormalPowerSeries<Mint>& terms,
                                       int degree) {
    assert(degree >= 0);
    if (degree == 0) return {};
    internal::assert_valid_sparse_fps(terms, degree);
    assert(!terms.empty() && terms[0].first == 0);

    const Mint inverse_constant = terms[0].second.inv();
    FormalPowerSeries<Mint> result(degree);
    result[0] = inverse_constant;
    for (int n = 1; n < degree; n++) {
        Mint coefficient = 0;
        for (int i = 1; i < int(terms.size()) && terms[i].first <= n; i++) {
            coefficient -= terms[i].second * result[n - terms[i].first];
        }
        result[n] = coefficient * inverse_constant;
    }
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> sparse_fps_log(const SparseFormalPowerSeries<Mint>& terms,
                                       int degree) {
    assert(degree >= 0);
    if (degree == 0) return {};
    assert(uint32_t(degree) < Mint::mod());
    internal::assert_valid_sparse_fps(terms, degree);
    assert(!terms.empty() && terms[0].first == 0 && terms[0].second == Mint(1));

    std::vector<Mint> inverse = internal::sparse_integer_inverses<Mint>(degree);
    FormalPowerSeries<Mint> result(degree);
    for (int n = 0; n + 1 < degree; n++) {
        Mint derivative_quotient = 0;
        for (int i = 1; i < int(terms.size()) && terms[i].first <= n + 1; i++) {
            const auto& [d, value] = terms[i];
            if (d == n + 1) derivative_quotient += Mint(d) * value;
            if (d <= n) {
                derivative_quotient -=
                    value * Mint(n - d + 1) * result[n - d + 1];
            }
        }
        result[n + 1] = derivative_quotient * inverse[n + 1];
    }
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> sparse_fps_exp(const SparseFormalPowerSeries<Mint>& terms,
                                       int degree) {
    assert(degree >= 0);
    if (degree == 0) return {};
    assert(uint32_t(degree) < Mint::mod());
    internal::assert_valid_sparse_fps(terms, degree);
    assert(terms.empty() || terms[0].first > 0);

    std::vector<Mint> inverse = internal::sparse_integer_inverses<Mint>(degree);
    FormalPowerSeries<Mint> result(degree);
    result[0] = Mint(1);
    for (int n = 1; n < degree; n++) {
        Mint coefficient = 0;
        for (const auto& [d, value] : terms) {
            if (d > n) break;
            coefficient += Mint(d) * value * result[n - d];
        }
        result[n] = coefficient * inverse[n];
    }
    return result;
}

template <class Mint>
FormalPowerSeries<Mint> sparse_fps_pow(const SparseFormalPowerSeries<Mint>& terms,
                                       long long exponent, int degree) {
    assert(exponent >= 0 && degree >= 0);
    if (degree == 0) return {};
    assert(uint32_t(degree) < Mint::mod());
    internal::assert_valid_sparse_fps(terms, degree);
    if (exponent == 0) {
        FormalPowerSeries<Mint> result(degree);
        result[0] = Mint(1);
        return result;
    }
    if (terms.empty()) return FormalPowerSeries<Mint>(degree);

    const int leading_degree = terms[0].first;
    if (leading_degree > 0 && exponent > (degree - 1) / leading_degree) {
        return FormalPowerSeries<Mint>(degree);
    }
    const int offset = int(leading_degree * exponent);
    const int normalized_degree = degree - offset;
    const Mint leading = terms[0].second;
    const Mint inverse_leading = leading.inv();
    SparseFormalPowerSeries<Mint> normalized;
    normalized.reserve(terms.size());
    for (const auto& [d, value] : terms) {
        if (d - leading_degree >= normalized_degree) break;
        normalized.emplace_back(d - leading_degree, value * inverse_leading);
    }

    FormalPowerSeries<Mint> unit =
        internal::sparse_unit_pow(normalized, Mint(exponent), normalized_degree);
    const Mint scale = leading.pow(exponent);
    FormalPowerSeries<Mint> result(degree);
    for (int i = 0; i < normalized_degree; i++) result[offset + i] = unit[i] * scale;
    return result;
}

template <class Mint>
std::optional<FormalPowerSeries<Mint>> sparse_fps_sqrt(
    const SparseFormalPowerSeries<Mint>& terms, int degree) {
    assert(degree >= 0);
    if (degree == 0) return FormalPowerSeries<Mint>();
    assert(uint32_t(degree) < Mint::mod());
    internal::assert_valid_sparse_fps(terms, degree);
    assert(Mint(2) != Mint(0));
    if (terms.empty()) return FormalPowerSeries<Mint>(degree);

    const int leading_degree = terms[0].first;
    if (leading_degree & 1) return std::nullopt;
    auto leading_root = m1une::math::modular_square_root(terms[0].second);
    if (!leading_root.has_value()) return std::nullopt;

    const int normalized_degree = degree - leading_degree;
    const Mint inverse_leading = terms[0].second.inv();
    SparseFormalPowerSeries<Mint> normalized;
    normalized.reserve(terms.size());
    for (const auto& [d, value] : terms) {
        normalized.emplace_back(d - leading_degree, value * inverse_leading);
    }
    FormalPowerSeries<Mint> unit = internal::sparse_unit_pow(
        normalized, Mint(2).inv(), normalized_degree);

    FormalPowerSeries<Mint> result(degree);
    const int offset = leading_degree / 2;
    for (int i = 0; i < normalized_degree; i++) {
        result[offset + i] = unit[i] * *leading_root;
    }
    return result;
}

}  // namespace fps
}  // namespace m1une


#line 19 "math/fps/all.hpp"


#line 1 "math/matrix/all.hpp"



#line 1 "math/matrix/adjugate.hpp"



#line 6 "math/matrix/adjugate.hpp"

#line 1 "math/matrix/matrix.hpp"



#line 9 "math/matrix/matrix.hpp"

namespace m1une {
namespace matrix {

template <class T>
class Matrix {
   private:
    int _rows;
    int _cols;
    std::vector<T> _data;

    static std::size_t storage_size(int rows, int cols) {
        assert(rows >= 0);
        assert(cols >= 0);
        return std::size_t(rows) * std::size_t(cols);
    }

   public:
    using value_type = T;

    Matrix() : _rows(0), _cols(0) {}

    Matrix(int rows, int cols, const T& value = T())
        : _rows(rows), _cols(cols), _data(storage_size(rows, cols), value) {}

    Matrix(int rows, int cols, std::vector<T> values)
        : _rows(rows), _cols(cols), _data(std::move(values)) {
        assert(rows >= 0);
        assert(cols >= 0);
        assert(_data.size() == std::size_t(rows) * std::size_t(cols));
    }

    explicit Matrix(const std::vector<std::vector<T>>& values)
        : _rows(int(values.size())), _cols(values.empty() ? 0 : int(values[0].size())),
          _data(storage_size(_rows, _cols)) {
        for (int row = 0; row < _rows; row++) {
            assert(int(values[std::size_t(row)].size()) == _cols);
            for (int col = 0; col < _cols; col++) {
                (*this)[row][col] = values[std::size_t(row)][std::size_t(col)];
            }
        }
    }

    int rows() const {
        return _rows;
    }

    int cols() const {
        return _cols;
    }

    bool empty() const {
        return _rows == 0 || _cols == 0;
    }

    std::vector<T>& data() {
        return _data;
    }

    const std::vector<T>& data() const {
        return _data;
    }

    T* operator[](int row) {
        assert(0 <= row && row < _rows);
        return _data.data() + std::size_t(row) * std::size_t(_cols);
    }

    const T* operator[](int row) const {
        assert(0 <= row && row < _rows);
        return _data.data() + std::size_t(row) * std::size_t(_cols);
    }

    T& operator()(int row, int col) {
        assert(0 <= col && col < _cols);
        return (*this)[row][col];
    }

    const T& operator()(int row, int col) const {
        assert(0 <= col && col < _cols);
        return (*this)[row][col];
    }

    static Matrix identity(int size) {
        assert(size >= 0);
        Matrix result(size, size);
        for (int i = 0; i < size; i++) result[i][i] = T(1);
        return result;
    }

    Matrix transposed() const {
        Matrix result(_cols, _rows);
        for (int row = 0; row < _rows; row++) {
            for (int col = 0; col < _cols; col++) {
                result[col][row] = (*this)[row][col];
            }
        }
        return result;
    }

    void swap_rows(int first, int second) {
        assert(0 <= first && first < _rows);
        assert(0 <= second && second < _rows);
        if (first == second) return;
        for (int col = 0; col < _cols; col++) {
            std::swap((*this)[first][col], (*this)[second][col]);
        }
    }

    Matrix& operator+=(const Matrix& rhs) {
        assert(_rows == rhs._rows && _cols == rhs._cols);
        for (std::size_t i = 0; i < _data.size(); i++) _data[i] += rhs._data[i];
        return *this;
    }

    Matrix& operator-=(const Matrix& rhs) {
        assert(_rows == rhs._rows && _cols == rhs._cols);
        for (std::size_t i = 0; i < _data.size(); i++) _data[i] -= rhs._data[i];
        return *this;
    }

    Matrix& operator*=(const T& scalar) {
        for (T& value : _data) value *= scalar;
        return *this;
    }

    Matrix& operator/=(const T& scalar) {
        for (T& value : _data) value /= scalar;
        return *this;
    }

    Matrix& operator*=(const Matrix& rhs) {
        return *this = *this * rhs;
    }

    Matrix operator+() const {
        return *this;
    }

    Matrix operator-() const {
        Matrix result = *this;
        for (T& value : result._data) value = T() - value;
        return result;
    }

    friend Matrix operator+(Matrix lhs, const Matrix& rhs) {
        return lhs += rhs;
    }

    friend Matrix operator-(Matrix lhs, const Matrix& rhs) {
        return lhs -= rhs;
    }

    friend Matrix operator*(Matrix lhs, const T& rhs) {
        return lhs *= rhs;
    }

    friend Matrix operator*(const T& lhs, Matrix rhs) {
        return rhs *= lhs;
    }

    friend Matrix operator/(Matrix lhs, const T& rhs) {
        return lhs /= rhs;
    }

    friend Matrix operator*(const Matrix& lhs, const Matrix& rhs) {
        assert(lhs._cols == rhs._rows);
        Matrix result(lhs._rows, rhs._cols);
        for (int row = 0; row < lhs._rows; row++) {
            T* output = result[row];
            for (int middle = 0; middle < lhs._cols; middle++) {
                const T coefficient = lhs[row][middle];
                if (coefficient == T()) continue;
                const T* input = rhs[middle];
                for (int col = 0; col < rhs._cols; col++) {
                    output[col] += coefficient * input[col];
                }
            }
        }
        return result;
    }

    friend std::vector<T> operator*(const Matrix& lhs, const std::vector<T>& rhs) {
        assert(lhs._cols == int(rhs.size()));
        std::vector<T> result(std::size_t(lhs._rows));
        for (int row = 0; row < lhs._rows; row++) {
            T value = T();
            for (int col = 0; col < lhs._cols; col++) {
                value += lhs[row][col] * rhs[std::size_t(col)];
            }
            result[std::size_t(row)] = value;
        }
        return result;
    }

    friend std::vector<T> operator*(const std::vector<T>& lhs, const Matrix& rhs) {
        assert(int(lhs.size()) == rhs._rows);
        std::vector<T> result(std::size_t(rhs._cols));
        for (int row = 0; row < rhs._rows; row++) {
            if (lhs[std::size_t(row)] == T()) continue;
            for (int col = 0; col < rhs._cols; col++) {
                result[std::size_t(col)] += lhs[std::size_t(row)] * rhs[row][col];
            }
        }
        return result;
    }

    bool operator==(const Matrix& rhs) const {
        return _rows == rhs._rows && _cols == rhs._cols && _data == rhs._data;
    }

    bool operator!=(const Matrix& rhs) const {
        return !(*this == rhs);
    }

    Matrix pow(std::uint64_t exponent) const {
        assert(_rows == _cols);
        Matrix result = identity(_rows);
        Matrix base = *this;
        while (exponent > 0) {
            if (exponent & 1) result *= base;
            exponent >>= 1;
            if (exponent > 0) base *= base;
        }
        return result;
    }
};

}  // namespace matrix
}  // namespace m1une


#line 8 "math/matrix/adjugate.hpp"

namespace m1une {
namespace matrix {

template <class T>
Matrix<T> adjugate(Matrix<T> matrix) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    Matrix<T> augmented(size, size * 2);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            augmented[row][col] = matrix[row][col];
        }
        augmented[row][size + row] = T(1);
    }

    std::vector<int> pivot_columns;
    T pivot_product = T(1);
    bool negate = false;
    for (int col = 0; col < size && int(pivot_columns.size()) < size; col++) {
        const int pivot_row = int(pivot_columns.size());
        int pivot = pivot_row;
        while (pivot < size && augmented[pivot][col] == T()) pivot++;
        if (pivot == size) continue;
        if (pivot != pivot_row) {
            augmented.swap_rows(pivot, pivot_row);
            negate = !negate;
        }

        const T pivot_value = augmented[pivot_row][col];
        pivot_product *= pivot_value;
        const T inverse_pivot = T(1) / pivot_value;
        for (int index = col; index < size; index++) {
            augmented[pivot_row][index] *= inverse_pivot;
        }
        for (int index = size; index < size * 2; index++) {
            augmented[pivot_row][index] *= inverse_pivot;
        }

        for (int row = 0; row < size; row++) {
            if (row == pivot_row || augmented[row][col] == T()) continue;
            const T factor = augmented[row][col];
            augmented[row][col] = T();
            for (int index = col + 1; index < size; index++) {
                augmented[row][index] -= factor * augmented[pivot_row][index];
            }
            for (int index = size; index < size * 2; index++) {
                augmented[row][index] -= factor * augmented[pivot_row][index];
            }
        }
        pivot_columns.push_back(col);
    }

    const int rank = int(pivot_columns.size());
    Matrix<T> result(size, size);
    if (rank + 1 < size) return result;

    if (rank == size) {
        const T determinant = negate ? T() - pivot_product : pivot_product;
        for (int row = 0; row < size; row++) {
            for (int col = 0; col < size; col++) {
                result[row][col] = determinant * augmented[row][size + col];
            }
        }
        return result;
    }

    int free_column = 0;
    while (free_column < rank && pivot_columns[free_column] == free_column) {
        free_column++;
    }
    std::vector<T> right_null(size);
    right_null[free_column] = T(1);
    for (int row = 0; row < rank; row++) {
        right_null[pivot_columns[row]] = T() - augmented[row][free_column];
    }

    T scale = pivot_product;
    if (negate != bool((size - 1 + free_column) & 1)) scale = T() - scale;
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            result[row][col] =
                scale * right_null[row] * augmented[size - 1][size + col];
        }
    }
    return result;
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/bit_matrix.hpp"



#line 11 "math/matrix/bit_matrix.hpp"
#include <string_view>
#line 14 "math/matrix/bit_matrix.hpp"

namespace m1une {
namespace matrix {

class BitMatrix {
   private:
    int _rows;
    int _cols;
    int _blocks;
    std::vector<std::uint64_t> _data;

    static int block_count(int cols) {
        assert(cols >= 0);
        return (cols + 63) / 64;
    }

    static std::size_t storage_size(int rows, int blocks) {
        assert(rows >= 0);
        return std::size_t(rows) * std::size_t(blocks);
    }

    std::size_t word_index(int row, int col) const {
        assert(0 <= row && row < _rows);
        assert(0 <= col && col < _cols);
        return std::size_t(row) * std::size_t(_blocks) +
               std::size_t(col / 64);
    }

    std::uint64_t trailing_mask() const {
        if ((_cols & 63) == 0) return ~std::uint64_t(0);
        return (std::uint64_t(1) << (_cols & 63)) - 1;
    }

   public:
    class BitReference {
       private:
        std::uint64_t* word;
        std::uint64_t mask;

       public:
        BitReference(std::uint64_t& word_value, std::uint64_t mask_value)
            : word(&word_value), mask(mask_value) {}

        operator bool() const {
            return (*word & mask) != 0;
        }

        BitReference& operator=(bool value) {
            if (value) {
                *word |= mask;
            } else {
                *word &= ~mask;
            }
            return *this;
        }

        BitReference& operator=(const BitReference& other) {
            return *this = bool(other);
        }

        void flip() {
            *word ^= mask;
        }
    };

    class RowReference {
       private:
        BitMatrix* matrix;
        int row;

       public:
        RowReference(BitMatrix& matrix_value, int row_value)
            : matrix(&matrix_value), row(row_value) {}

        BitReference operator[](int col) const {
            return (*matrix)(row, col);
        }
    };

    class ConstRowReference {
       private:
        const BitMatrix* matrix;
        int row;

       public:
        ConstRowReference(const BitMatrix& matrix_value, int row_value)
            : matrix(&matrix_value), row(row_value) {}

        bool operator[](int col) const {
            return (*matrix)(row, col);
        }
    };

    BitMatrix() : _rows(0), _cols(0), _blocks(0) {}

    BitMatrix(int rows, int cols, bool value = false)
        : _rows(rows),
          _cols(cols),
          _blocks(block_count(cols)),
          _data(
              storage_size(rows, _blocks),
              value ? ~std::uint64_t(0) : std::uint64_t(0)
          ) {
        assert(rows >= 0);
        if (value && _blocks > 0) {
            const std::uint64_t mask = trailing_mask();
            for (int row = 0; row < _rows; row++) {
                _data[
                    std::size_t(row + 1) * std::size_t(_blocks) - 1
                ] &= mask;
            }
        }
    }

    int rows() const {
        return _rows;
    }

    int cols() const {
        return _cols;
    }

    int blocks_per_row() const {
        return _blocks;
    }

    bool empty() const {
        return _rows == 0 || _cols == 0;
    }

    RowReference operator[](int row) {
        assert(0 <= row && row < _rows);
        return RowReference(*this, row);
    }

    ConstRowReference operator[](int row) const {
        assert(0 <= row && row < _rows);
        return ConstRowReference(*this, row);
    }

    BitReference operator()(int row, int col) {
        const std::size_t index = word_index(row, col);
        return BitReference(_data[index], std::uint64_t(1) << (col & 63));
    }

    bool operator()(int row, int col) const {
        const std::size_t index = word_index(row, col);
        return (_data[index] >> (col & 63)) & 1;
    }

    bool get(int row, int col) const {
        return (*this)(row, col);
    }

    void set(int row, int col, bool value = true) {
        (*this)(row, col) = value;
    }

    void reset(int row, int col) {
        set(row, col, false);
    }

    void flip(int row, int col) {
        (*this)(row, col).flip();
    }

    void clear() {
        std::fill(_data.begin(), _data.end(), std::uint64_t(0));
    }

    void set_row(int row, std::string_view bits) {
        assert(0 <= row && row < _rows);
        assert(int(bits.size()) == _cols);
        const std::size_t offset =
            std::size_t(row) * std::size_t(_blocks);
        std::fill(
            _data.begin() + std::ptrdiff_t(offset),
            _data.begin() + std::ptrdiff_t(offset + std::size_t(_blocks)),
            std::uint64_t(0)
        );
        for (int col = 0; col < _cols; col++) {
            assert(bits[std::size_t(col)] == '0' || bits[std::size_t(col)] == '1');
            if (bits[std::size_t(col)] == '1') set(row, col);
        }
    }

    std::string row_string(int row) const {
        assert(0 <= row && row < _rows);
        std::string result(std::size_t(_cols), '0');
        for (int col = 0; col < _cols; col++) {
            if (get(row, col)) result[std::size_t(col)] = '1';
        }
        return result;
    }

    static BitMatrix identity(int size) {
        assert(size >= 0);
        BitMatrix result(size, size);
        for (int index = 0; index < size; index++) result.set(index, index);
        return result;
    }

    BitMatrix transposed() const {
        BitMatrix result(_cols, _rows);
        for (int row = 0; row < _rows; row++) {
            for (int col = 0; col < _cols; col++) {
                if (get(row, col)) result.set(col, row);
            }
        }
        return result;
    }

    void swap_rows(int first, int second) {
        assert(0 <= first && first < _rows);
        assert(0 <= second && second < _rows);
        if (first == second) return;
        const std::size_t first_offset =
            std::size_t(first) * std::size_t(_blocks);
        const std::size_t second_offset =
            std::size_t(second) * std::size_t(_blocks);
        for (int block = 0; block < _blocks; block++) {
            std::swap(
                _data[first_offset + std::size_t(block)],
                _data[second_offset + std::size_t(block)]
            );
        }
    }

    void xor_rows(int target, int source, int first_col = 0) {
        assert(0 <= target && target < _rows);
        assert(0 <= source && source < _rows);
        assert(0 <= first_col && first_col <= _cols);
        if (first_col == _cols) return;
        const std::size_t target_offset =
            std::size_t(target) * std::size_t(_blocks);
        const std::size_t source_offset =
            std::size_t(source) * std::size_t(_blocks);
        const int first_block = first_col / 64;
        const int first_bit = first_col & 63;
        if (first_bit != 0) {
            const std::uint64_t mask = ~std::uint64_t(0) << first_bit;
            _data[target_offset + std::size_t(first_block)] ^=
                _data[source_offset + std::size_t(first_block)] & mask;
        } else {
            _data[target_offset + std::size_t(first_block)] ^=
                _data[source_offset + std::size_t(first_block)];
        }
        for (int block = first_block + 1; block < _blocks; block++) {
            _data[target_offset + std::size_t(block)] ^=
                _data[source_offset + std::size_t(block)];
        }
    }

    BitMatrix& operator^=(const BitMatrix& rhs) {
        assert(_rows == rhs._rows && _cols == rhs._cols);
        for (std::size_t index = 0; index < _data.size(); index++) {
            _data[index] ^= rhs._data[index];
        }
        return *this;
    }

    BitMatrix& operator+=(const BitMatrix& rhs) {
        return *this ^= rhs;
    }

    BitMatrix& operator-=(const BitMatrix& rhs) {
        return *this ^= rhs;
    }

    BitMatrix& operator*=(const BitMatrix& rhs) {
        return *this = *this * rhs;
    }

    friend BitMatrix operator^(BitMatrix lhs, const BitMatrix& rhs) {
        return lhs ^= rhs;
    }

    friend BitMatrix operator+(BitMatrix lhs, const BitMatrix& rhs) {
        return lhs += rhs;
    }

    friend BitMatrix operator-(BitMatrix lhs, const BitMatrix& rhs) {
        return lhs -= rhs;
    }

    friend BitMatrix operator*(const BitMatrix& lhs, const BitMatrix& rhs) {
        assert(lhs._cols == rhs._rows);
        BitMatrix result(lhs._rows, rhs._cols);
        for (int row = 0; row < lhs._rows; row++) {
            const std::size_t lhs_offset =
                std::size_t(row) * std::size_t(lhs._blocks);
            const std::size_t result_offset =
                std::size_t(row) * std::size_t(result._blocks);
            for (int lhs_block = 0; lhs_block < lhs._blocks; lhs_block++) {
                std::uint64_t word =
                    lhs._data[lhs_offset + std::size_t(lhs_block)];
                while (word != 0) {
                    const int bit = std::countr_zero(word);
                    const int middle = lhs_block * 64 + bit;
                    const std::size_t rhs_offset =
                        std::size_t(middle) * std::size_t(rhs._blocks);
                    for (int block = 0; block < rhs._blocks; block++) {
                        result._data[result_offset + std::size_t(block)] ^=
                            rhs._data[rhs_offset + std::size_t(block)];
                    }
                    word &= word - 1;
                }
            }
        }
        return result;
    }

    bool operator==(const BitMatrix& rhs) const {
        return
            _rows == rhs._rows && _cols == rhs._cols && _data == rhs._data;
    }

    bool operator!=(const BitMatrix& rhs) const {
        return !(*this == rhs);
    }

    BitMatrix pow(std::uint64_t exponent) const {
        assert(_rows == _cols);
        BitMatrix result = identity(_rows);
        BitMatrix base = *this;
        while (exponent > 0) {
            if (exponent & 1) result *= base;
            exponent >>= 1;
            if (exponent > 0) base *= base;
        }
        return result;
    }
};

namespace bit_matrix_detail {

inline std::vector<int> row_reduce(
    BitMatrix& matrix,
    int pivot_col_limit,
    bool reduced
) {
    assert(0 <= pivot_col_limit && pivot_col_limit <= matrix.cols());
    std::vector<int> pivot_columns;
    int pivot_row = 0;
    for (
        int col = 0;
        col < pivot_col_limit && pivot_row < matrix.rows();
        col++
    ) {
        int pivot = -1;
        for (int row = pivot_row; row < matrix.rows(); row++) {
            if (matrix.get(row, col)) {
                pivot = row;
                break;
            }
        }
        if (pivot == -1) continue;
        matrix.swap_rows(pivot_row, pivot);

        const int first_row = reduced ? 0 : pivot_row + 1;
        for (int row = first_row; row < matrix.rows(); row++) {
            if (row != pivot_row && matrix.get(row, col)) {
                matrix.xor_rows(row, pivot_row, col);
            }
        }
        pivot_columns.push_back(col);
        pivot_row++;
    }
    return pivot_columns;
}

}  // namespace bit_matrix_detail

struct BitRowReduction {
    BitMatrix matrix;
    std::vector<int> pivot_columns;

    int rank() const {
        return int(pivot_columns.size());
    }
};

inline BitRowReduction reduced_row_echelon_form(BitMatrix matrix) {
    BitRowReduction result;
    result.pivot_columns = bit_matrix_detail::row_reduce(
        matrix,
        matrix.cols(),
        true
    );
    result.matrix = std::move(matrix);
    return result;
}

inline int matrix_rank(BitMatrix matrix) {
    if (matrix.rows() > matrix.cols()) matrix = matrix.transposed();
    return int(bit_matrix_detail::row_reduce(
        matrix,
        matrix.cols(),
        false
    ).size());
}

inline bool determinant(const BitMatrix& matrix) {
    assert(matrix.rows() == matrix.cols());
    return matrix_rank(matrix) == matrix.rows();
}

inline std::optional<BitMatrix> inverse(const BitMatrix& matrix) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    BitMatrix augmented(size, 2 * size);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            if (matrix.get(row, col)) augmented.set(row, col);
        }
        augmented.set(row, size + row);
    }

    const std::vector<int> pivots = bit_matrix_detail::row_reduce(
        augmented,
        size,
        true
    );
    if (int(pivots.size()) != size) return std::nullopt;

    BitMatrix result(size, size);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            if (augmented.get(row, size + col)) result.set(row, col);
        }
    }
    return result;
}

struct BitLinearSystemResult {
    bool consistent = false;
    std::vector<bool> particular_solution;
    std::vector<std::vector<bool>> nullspace_basis;
    std::vector<int> pivot_columns;

    int rank() const {
        return int(pivot_columns.size());
    }

    int nullity() const {
        return consistent ? int(nullspace_basis.size()) : 0;
    }

    bool has_unique_solution() const {
        return consistent && nullspace_basis.empty();
    }
};

inline BitLinearSystemResult solve_linear_system(
    const BitMatrix& coefficients,
    const std::vector<bool>& constants
) {
    assert(coefficients.rows() == int(constants.size()));
    const int equation_count = coefficients.rows();
    const int variable_count = coefficients.cols();
    BitMatrix augmented(equation_count, variable_count + 1);
    for (int row = 0; row < equation_count; row++) {
        for (int col = 0; col < variable_count; col++) {
            if (coefficients.get(row, col)) augmented.set(row, col);
        }
        if (constants[std::size_t(row)]) augmented.set(row, variable_count);
    }

    BitLinearSystemResult result;
    result.pivot_columns = bit_matrix_detail::row_reduce(
        augmented,
        variable_count,
        true
    );
    for (int row = result.rank(); row < equation_count; row++) {
        if (augmented.get(row, variable_count)) return result;
    }

    result.consistent = true;
    result.particular_solution.assign(std::size_t(variable_count), false);
    std::vector<bool> is_pivot(std::size_t(variable_count), false);
    for (int row = 0; row < result.rank(); row++) {
        const int col = result.pivot_columns[std::size_t(row)];
        is_pivot[std::size_t(col)] = true;
        result.particular_solution[std::size_t(col)] =
            augmented.get(row, variable_count);
    }

    for (int free_col = 0; free_col < variable_count; free_col++) {
        if (is_pivot[std::size_t(free_col)]) continue;
        std::vector<bool> direction(std::size_t(variable_count), false);
        direction[std::size_t(free_col)] = true;
        for (int row = 0; row < result.rank(); row++) {
            const int pivot_col = result.pivot_columns[std::size_t(row)];
            direction[std::size_t(pivot_col)] = augmented.get(row, free_col);
        }
        result.nullspace_basis.push_back(std::move(direction));
    }
    return result;
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/characteristic_polynomial.hpp"



#line 8 "math/matrix/characteristic_polynomial.hpp"

#line 10 "math/matrix/characteristic_polynomial.hpp"

namespace m1une {
namespace matrix {

template <class T>
std::vector<T> characteristic_polynomial(Matrix<T> matrix) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();

    for (int col = 0; col + 2 < size; col++) {
        int pivot = col + 1;
        while (pivot < size && matrix[pivot][col] == T()) pivot++;
        if (pivot == size) continue;

        if (pivot != col + 1) {
            matrix.swap_rows(pivot, col + 1);
            for (int row = 0; row < size; row++) {
                std::swap(matrix[row][pivot], matrix[row][col + 1]);
            }
        }

        const T inverse_pivot = T(1) / matrix[col + 1][col];
        for (int row = col + 2; row < size; row++) {
            if (matrix[row][col] == T()) continue;
            const T factor = matrix[row][col] * inverse_pivot;
            for (int j = col; j < size; j++) {
                matrix[row][j] -= factor * matrix[col + 1][j];
            }
            for (int i = 0; i < size; i++) {
                matrix[i][col + 1] += factor * matrix[i][row];
            }
        }
    }

    std::vector<std::vector<T>> polynomial(std::size_t(size + 1));
    polynomial[0].assign(1, T(1));
    for (int leading_size = 1; leading_size <= size; leading_size++) {
        const int last = leading_size - 1;
        polynomial[std::size_t(leading_size)].assign(
            std::size_t(leading_size + 1),
            T()
        );
        const std::vector<T>& previous =
            polynomial[std::size_t(leading_size - 1)];
        std::vector<T>& current = polynomial[std::size_t(leading_size)];

        for (int degree = 0; degree < leading_size; degree++) {
            current[std::size_t(degree)] -=
                previous[std::size_t(degree)] * matrix[last][last];
            current[std::size_t(degree + 1)] +=
                previous[std::size_t(degree)];
        }

        T subdiagonal_product = T(1);
        for (int row = last - 1; row >= 0; row--) {
            subdiagonal_product *= matrix[row + 1][row];
            const T factor = subdiagonal_product * matrix[row][last];
            if (factor == T()) continue;
            for (int degree = 0; degree <= row; degree++) {
                current[std::size_t(degree)] -=
                    factor * polynomial[std::size_t(row)][std::size_t(degree)];
            }
        }
    }
    return polynomial[std::size_t(size)];
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/determinant_mod.hpp"



#line 7 "math/matrix/determinant_mod.hpp"

#line 9 "math/matrix/determinant_mod.hpp"

namespace m1une {
namespace matrix {

namespace detail {

inline std::uint64_t determinant_multiply_mod(std::uint64_t lhs,
                                              std::uint64_t rhs,
                                              std::uint64_t modulus) {
    return std::uint64_t(static_cast<unsigned __int128>(lhs) * rhs % modulus);
}

inline std::uint64_t determinant_subtract_product_mod(
    std::uint64_t value, std::uint64_t lhs, std::uint64_t rhs,
    std::uint64_t modulus) {
    const std::uint64_t product = determinant_multiply_mod(lhs, rhs, modulus);
    return std::uint64_t((static_cast<unsigned __int128>(value) + modulus - product) %
                         modulus);
}

inline std::uint64_t determinant_add_products_mod(
    std::uint64_t first_lhs, std::uint64_t first_rhs,
    std::uint64_t second_lhs, std::uint64_t second_rhs,
    std::uint64_t modulus) {
    const std::uint64_t first =
        determinant_multiply_mod(first_lhs, first_rhs, modulus);
    const std::uint64_t second =
        determinant_multiply_mod(second_lhs, second_rhs, modulus);
    return std::uint64_t((static_cast<unsigned __int128>(first) + second) % modulus);
}

template <class Integer>
std::uint64_t determinant_normalize(Integer value, std::uint64_t modulus) {
    static_assert(std::is_integral_v<Integer>);
    static_assert(sizeof(Integer) <= sizeof(std::uint64_t));
    if constexpr (std::is_signed_v<Integer>) {
        __int128 residue = static_cast<__int128>(value) % static_cast<__int128>(modulus);
        if (residue < 0) residue += modulus;
        return std::uint64_t(residue);
    } else {
        return std::uint64_t(static_cast<unsigned __int128>(value) % modulus);
    }
}

}  // namespace detail

template <class Integer>
std::uint64_t determinant_mod(const Matrix<Integer>& matrix,
                              std::uint64_t modulus) {
    static_assert(std::is_integral_v<Integer>);
    assert(matrix.rows() == matrix.cols());
    assert(modulus > 0);
    const int size = matrix.rows();
    if (size == 0) return std::uint64_t(1) % modulus;

    Matrix<std::uint64_t> reduced(size, size);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            reduced[row][col] =
                detail::determinant_normalize(matrix[row][col], modulus);
        }
    }

    std::uint64_t result = std::uint64_t(1) % modulus;
    bool negate = false;
    for (int col = 0; col < size; col++) {
        int pivot = col;
        while (pivot < size && reduced[pivot][col] == 0) pivot++;
        if (pivot == size) return 0;
        if (pivot != col) {
            reduced.swap_rows(pivot, col);
            negate = !negate;
        }

        for (int row = col + 1; row < size; row++) {
            std::uint64_t upper = reduced[col][col];
            std::uint64_t lower = reduced[row][col];
            if (lower == 0) continue;

            std::uint64_t upper_upper = 1 % modulus;
            std::uint64_t upper_lower = 0;
            std::uint64_t lower_upper = 0;
            std::uint64_t lower_lower = 1 % modulus;
            while (upper != 0 && lower != 0) {
                if (upper < lower) {
                    const std::uint64_t quotient = lower / upper;
                    lower -= quotient * upper;
                    lower_upper = detail::determinant_subtract_product_mod(
                        lower_upper, quotient, upper_upper, modulus);
                    lower_lower = detail::determinant_subtract_product_mod(
                        lower_lower, quotient, upper_lower, modulus);
                } else {
                    const std::uint64_t quotient = upper / lower;
                    upper -= quotient * lower;
                    upper_upper = detail::determinant_subtract_product_mod(
                        upper_upper, quotient, lower_upper, modulus);
                    upper_lower = detail::determinant_subtract_product_mod(
                        upper_lower, quotient, lower_lower, modulus);
                }
            }

            for (int index = col; index < size; index++) {
                const std::uint64_t old_upper = reduced[col][index];
                const std::uint64_t old_lower = reduced[row][index];
                reduced[col][index] = detail::determinant_add_products_mod(
                    upper_upper, old_upper, upper_lower, old_lower, modulus);
                reduced[row][index] = detail::determinant_add_products_mod(
                    lower_upper, old_upper, lower_lower, old_lower, modulus);
            }
            if (upper == 0) {
                reduced.swap_rows(col, row);
                negate = !negate;
            }
        }

        result = detail::determinant_multiply_mod(
            result, reduced[col][col], modulus);
        if (result == 0) return 0;
    }
    return negate ? modulus - result : result;
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/hafnian.hpp"



#line 7 "math/matrix/hafnian.hpp"

#line 9 "math/matrix/hafnian.hpp"

namespace m1une {
namespace matrix {
namespace internal {

template <class T>
class HafnianSolver {
    using Polynomial = std::vector<T>;
    using PolynomialMatrix = std::vector<std::vector<Polynomial>>;

    int _degree;

    void add_shifted_product(Polynomial& result, const Polynomial& first,
                             const Polynomial& second) const {
        for (int first_degree = 0; first_degree < _degree; first_degree++) {
            for (int second_degree = 0;
                 first_degree + second_degree + 1 < _degree;
                 second_degree++) {
                result[first_degree + second_degree + 1] +=
                    first[first_degree] * second[second_degree];
            }
        }
    }

    Polynomial solve(PolynomialMatrix matrix) const {
        if (matrix.empty()) {
            Polynomial result(_degree);
            result[0] = T(1);
            return result;
        }

        std::vector<Polynomial> first = std::move(matrix.back());
        matrix.pop_back();
        std::vector<Polynomial> second = std::move(matrix.back());
        matrix.pop_back();
        const int remaining = int(matrix.size());
        Polynomial first_to_pair = std::move(first[remaining]);

        Polynomial result = solve(matrix);
        for (T& coefficient : result) coefficient = T() - coefficient;

        for (int row = 0; row < remaining; row++) {
            for (int col = 0; col < row; col++) {
                add_shifted_product(matrix[row][col], first[row], second[col]);
                add_shifted_product(matrix[row][col], second[row], first[col]);
            }
        }

        Polynomial with_connections = solve(std::move(matrix));
        add_shifted_product(result, first_to_pair, with_connections);
        for (int degree = 0; degree < _degree; degree++) {
            result[degree] += with_connections[degree];
        }
        return result;
    }

   public:
    explicit HafnianSolver(int size) : _degree(size / 2 + 1) {}

    T operator()(const Matrix<T>& matrix) const {
        const int size = matrix.rows();
        PolynomialMatrix polynomial_matrix(size);
        for (int row = 0; row < size; row++) {
            polynomial_matrix[row].assign(row, Polynomial(_degree));
            for (int col = 0; col < row; col++) {
                polynomial_matrix[row][col][0] = matrix[row][col];
            }
        }
        return solve(std::move(polynomial_matrix)).back();
    }
};

}  // namespace internal

// Returns the hafnian of an even-dimensional symmetric zero-diagonal matrix.
template <class T>
T hafnian(const Matrix<T>& matrix) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    assert(size % 2 == 0);

#ifndef NDEBUG
    for (int row = 0; row < size; row++) {
        assert(matrix[row][row] == T());
        for (int col = row + 1; col < size; col++) {
            assert(matrix[row][col] == matrix[col][row]);
        }
    }
#endif

    return internal::HafnianSolver<T>(size)(matrix);
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/linear_algebra.hpp"



#line 7 "math/matrix/linear_algebra.hpp"

#line 9 "math/matrix/linear_algebra.hpp"

namespace m1une {
namespace matrix {

template <class T>
constexpr T default_epsilon() {
    if constexpr (std::is_floating_point_v<T>) {
        return T(1e-10);
    } else {
        return T();
    }
}

namespace detail {

template <class T>
T matrix_abs(T value) {
    return value < T() ? T() - value : value;
}

template <class T>
bool is_zero(const T& value, const T& eps) {
    if constexpr (std::is_floating_point_v<T>) {
        return matrix_abs(value) <= eps;
    } else {
        (void)eps;
        return value == T();
    }
}

template <class T>
int choose_pivot(const Matrix<T>& matrix, int first_row, int col, const T& eps) {
    int pivot = -1;
    if constexpr (std::is_floating_point_v<T>) {
        for (int row = first_row; row < matrix.rows(); row++) {
            if (is_zero(matrix[row][col], eps)) continue;
            if (pivot == -1 || matrix_abs(matrix[pivot][col]) < matrix_abs(matrix[row][col])) {
                pivot = row;
            }
        }
    } else {
        for (int row = first_row; row < matrix.rows(); row++) {
            if (!is_zero(matrix[row][col], eps)) {
                pivot = row;
                break;
            }
        }
    }
    return pivot;
}

template <class T>
std::vector<int> row_reduce(Matrix<T>& matrix, int pivot_col_limit, const T& eps,
                            bool reduced) {
    std::vector<int> pivot_columns;
    int pivot_row = 0;
    for (int col = 0; col < pivot_col_limit && pivot_row < matrix.rows(); col++) {
        int pivot = choose_pivot(matrix, pivot_row, col, eps);
        if (pivot == -1) continue;
        matrix.swap_rows(pivot_row, pivot);

        const T pivot_value = matrix[pivot_row][col];
        if (reduced) {
            for (int j = col; j < matrix.cols(); j++) matrix[pivot_row][j] /= pivot_value;
        }

        const int first_row = reduced ? 0 : pivot_row + 1;
        for (int row = first_row; row < matrix.rows(); row++) {
            if (row == pivot_row || is_zero(matrix[row][col], eps)) continue;
            T factor = matrix[row][col];
            if (!reduced) factor /= pivot_value;
            matrix[row][col] = T();
            for (int j = col + 1; j < matrix.cols(); j++) {
                matrix[row][j] -= factor * matrix[pivot_row][j];
            }
        }

        pivot_columns.push_back(col);
        pivot_row++;
    }

    if constexpr (std::is_floating_point_v<T>) {
        for (T& value : matrix.data()) {
            if (is_zero(value, eps)) value = T();
        }
    }
    return pivot_columns;
}

}  // namespace detail

template <class T>
struct RowReduction {
    Matrix<T> matrix;
    std::vector<int> pivot_columns;

    int rank() const {
        return int(pivot_columns.size());
    }
};

template <class T>
RowReduction<T> reduced_row_echelon_form(Matrix<T> matrix,
                                         T eps = default_epsilon<T>()) {
    RowReduction<T> result;
    result.pivot_columns = detail::row_reduce(matrix, matrix.cols(), eps, true);
    result.matrix = std::move(matrix);
    return result;
}

template <class T>
int matrix_rank(Matrix<T> matrix, T eps = default_epsilon<T>()) {
    return int(detail::row_reduce(matrix, matrix.cols(), eps, false).size());
}

template <class T>
T determinant(Matrix<T> matrix, T eps = default_epsilon<T>()) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    T result = T(1);
    bool negate = false;

    for (int col = 0; col < size; col++) {
        int pivot = detail::choose_pivot(matrix, col, col, eps);
        if (pivot == -1) return T();
        if (pivot != col) {
            matrix.swap_rows(pivot, col);
            negate = !negate;
        }

        const T pivot_value = matrix[col][col];
        result *= pivot_value;
        for (int row = col + 1; row < size; row++) {
            if (detail::is_zero(matrix[row][col], eps)) continue;
            const T factor = matrix[row][col] / pivot_value;
            matrix[row][col] = T();
            for (int j = col + 1; j < size; j++) {
                matrix[row][j] -= factor * matrix[col][j];
            }
        }
    }
    return negate ? T() - result : result;
}

template <class T>
std::optional<Matrix<T>> inverse(const Matrix<T>& matrix,
                                 T eps = default_epsilon<T>()) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    Matrix<T> augmented(size, size * 2);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            augmented[row][col] = matrix[row][col];
        }
        augmented[row][size + row] = T(1);
    }

    const std::vector<int> pivots = detail::row_reduce(augmented, size, eps, true);
    if (int(pivots.size()) != size) return std::nullopt;

    Matrix<T> result(size, size);
    for (int row = 0; row < size; row++) {
        for (int col = 0; col < size; col++) {
            result[row][col] = augmented[row][size + col];
        }
    }
    return result;
}

template <class T>
struct LinearSystemResult {
    bool consistent = false;
    std::vector<T> particular_solution;
    std::vector<std::vector<T>> nullspace_basis;
    std::vector<int> pivot_columns;

    int rank() const {
        return int(pivot_columns.size());
    }

    int nullity() const {
        return consistent ? int(nullspace_basis.size()) : 0;
    }

    bool has_unique_solution() const {
        return consistent && nullspace_basis.empty();
    }
};

template <class T>
LinearSystemResult<T> solve_linear_system(const Matrix<T>& coefficients,
                                          const std::vector<T>& constants,
                                          T eps = default_epsilon<T>()) {
    assert(coefficients.rows() == int(constants.size()));
    const int equation_count = coefficients.rows();
    const int variable_count = coefficients.cols();
    Matrix<T> augmented(equation_count, variable_count + 1);
    for (int row = 0; row < equation_count; row++) {
        for (int col = 0; col < variable_count; col++) {
            augmented[row][col] = coefficients[row][col];
        }
        augmented[row][variable_count] = constants[std::size_t(row)];
    }

    LinearSystemResult<T> result;
    result.pivot_columns =
        detail::row_reduce(augmented, variable_count, eps, true);

    for (int row = result.rank(); row < equation_count; row++) {
        bool zero_left = true;
        for (int col = 0; col < variable_count; col++) {
            if (!detail::is_zero(augmented[row][col], eps)) {
                zero_left = false;
                break;
            }
        }
        if (zero_left && !detail::is_zero(augmented[row][variable_count], eps)) {
            return result;
        }
    }

    result.consistent = true;
    result.particular_solution.assign(std::size_t(variable_count), T());
    std::vector<bool> is_pivot(std::size_t(variable_count), false);
    for (int row = 0; row < result.rank(); row++) {
        const int col = result.pivot_columns[std::size_t(row)];
        is_pivot[std::size_t(col)] = true;
        result.particular_solution[std::size_t(col)] = augmented[row][variable_count];
    }

    for (int free_col = 0; free_col < variable_count; free_col++) {
        if (is_pivot[std::size_t(free_col)]) continue;
        std::vector<T> direction(static_cast<std::size_t>(variable_count));
        direction[std::size_t(free_col)] = T(1);
        for (int row = 0; row < result.rank(); row++) {
            const int pivot_col = result.pivot_columns[std::size_t(row)];
            direction[std::size_t(pivot_col)] = T() - augmented[row][free_col];
        }
        result.nullspace_basis.push_back(std::move(direction));
    }
    return result;
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/pfaffian.hpp"



#line 6 "math/matrix/pfaffian.hpp"

#line 8 "math/matrix/pfaffian.hpp"

namespace m1une {
namespace matrix {

// Returns the Pfaffian of an even-dimensional alternating matrix over a field.
template <class T>
T pfaffian(Matrix<T> matrix) {
    assert(matrix.rows() == matrix.cols());
    const int size = matrix.rows();
    assert(size % 2 == 0);

#ifndef NDEBUG
    for (int row = 0; row < size; row++) {
        assert(matrix[row][row] == T());
        for (int col = row + 1; col < size; col++) {
            assert(matrix[row][col] == T() - matrix[col][row]);
        }
    }
#endif

    T result = T(1);
    for (int first = 0; first < size; first += 2) {
        int pivot = first + 1;
        while (pivot < size && matrix[first][pivot] == T()) pivot++;
        if (pivot == size) return T();

        if (pivot != first + 1) {
            matrix.swap_rows(pivot, first + 1);
            for (int row = 0; row < size; row++) {
                std::swap(matrix[row][pivot], matrix[row][first + 1]);
            }
            result = T() - result;
        }

        const int second = first + 1;
        const T pivot_value = matrix[first][second];
        result *= pivot_value;
        const T inverse_pivot = T(1) / pivot_value;

        for (int row = second + 1; row < size; row++) {
            for (int col = row + 1; col < size; col++) {
                matrix[row][col] +=
                    (matrix[second][row] * matrix[first][col] -
                     matrix[first][row] * matrix[second][col]) *
                    inverse_pivot;
                matrix[col][row] = T() - matrix[row][col];
            }
        }
    }
    return result;
}

}  // namespace matrix
}  // namespace m1une


#line 1 "math/matrix/sparse_determinant.hpp"



#line 8 "math/matrix/sparse_determinant.hpp"

namespace m1une {
namespace matrix {

template <class T>
struct SparseMatrixEntry {
    int row;
    int col;
    T value;
};

namespace internal {

struct SparseDeterminantRandom {
    std::uint64_t state;

    explicit SparseDeterminantRandom(std::uint64_t seed) : state(seed) {}

    std::uint64_t operator()() {
        std::uint64_t value = (state += 0x9e3779b97f4a7c15ULL);
        value = (value ^ (value >> 30)) * 0xbf58476d1ce4e5b9ULL;
        value = (value ^ (value >> 27)) * 0x94d049bb133111ebULL;
        return value ^ (value >> 31);
    }
};

template <class T>
std::vector<T> berlekamp_massey(const std::vector<T>& sequence) {
    std::vector<T> recurrence(1, T(1));
    std::vector<T> previous(1, T(1));
    int degree = 0;
    int shift = 1;
    T previous_discrepancy = T(1);

    for (int index = 0; index < int(sequence.size()); index++) {
        T discrepancy = sequence[index];
        for (int i = 1; i <= degree; i++) {
            discrepancy += recurrence[i] * sequence[index - i];
        }
        if (discrepancy == T()) {
            shift++;
            continue;
        }

        const T factor = discrepancy / previous_discrepancy;
        std::vector<T> old_recurrence = recurrence;
        if (int(recurrence.size()) < int(previous.size()) + shift) {
            recurrence.resize(previous.size() + std::size_t(shift), T());
        }
        for (int i = 0; i < int(previous.size()); i++) {
            recurrence[i + shift] -= factor * previous[i];
        }

        if (2 * degree <= index) {
            degree = index + 1 - degree;
            previous = std::move(old_recurrence);
            previous_discrepancy = discrepancy;
            shift = 1;
        } else {
            shift++;
        }
    }
    recurrence.resize(std::size_t(degree + 1));
    return recurrence;
}

}  // namespace internal

// Randomized black-box determinant over a finite field. random_nonzero must
// return independent nonzero field elements.
template <class T, class RandomValue>
T sparse_determinant_with_randomizer(
    int size, const std::vector<SparseMatrixEntry<T>>& entries,
    RandomValue random_nonzero
) {
    assert(size >= 0);
    for (const SparseMatrixEntry<T>& entry : entries) {
        assert(0 <= entry.row && entry.row < size);
        assert(0 <= entry.col && entry.col < size);
    }
    if (size == 0) return T(1);

    auto random_vector = [&]() {
        std::vector<T> result(size);
        for (T& value : result) {
            value = random_nonzero();
            assert(value != T());
        }
        return result;
    };

    while (true) {
        std::vector<T> diagonal = random_vector();
        std::vector<T> left = random_vector();
        std::vector<T> state = random_vector();
        std::vector<T> sequence(std::size_t(2 * size));

        for (int step = 0; step < 2 * size; step++) {
            for (int i = 0; i < size; i++) sequence[step] += left[i] * state[i];
            for (int i = 0; i < size; i++) state[i] *= diagonal[i];

            std::vector<T> next(size);
            for (const SparseMatrixEntry<T>& entry : entries) {
                next[entry.row] += entry.value * state[entry.col];
            }
            state = std::move(next);
        }

        std::vector<T> recurrence = internal::berlekamp_massey(sequence);
        if (recurrence.back() == T()) return T();
        if (int(recurrence.size()) != size + 1) continue;

        T determinant = recurrence.back();
        if (size % 2 == 1) determinant = T() - determinant;
        for (const T& value : diagonal) determinant /= value;
        return determinant;
    }
}

template <class T>
T sparse_determinant(
    int size, const std::vector<SparseMatrixEntry<T>>& entries,
    std::uint64_t seed = 0x243f6a8885a308d3ULL
) {
    const std::uint64_t modulus = T::mod();
    assert(modulus > 1);
    internal::SparseDeterminantRandom random(seed);
    auto random_nonzero = [&]() {
        return T(1 + random() % (modulus - 1));
    };
    return sparse_determinant_with_randomizer<T>(size, entries, random_nonzero);
}

}  // namespace matrix
}  // namespace m1une


#line 13 "math/matrix/all.hpp"


#line 1 "math/modular_kth_root.hpp"



#line 11 "math/modular_kth_root.hpp"

#line 13 "math/modular_kth_root.hpp"

namespace m1une {
namespace math {

namespace modular_kth_root_detail {

inline uint64_t multiply(uint64_t first, uint64_t second, uint64_t mod) {
    return static_cast<uint64_t>(static_cast<__uint128_t>(first) * second % mod);
}

inline uint64_t power(uint64_t base, uint64_t exponent, uint64_t mod) {
    uint64_t result = 1 % mod;
    while (exponent != 0) {
        if (exponent & 1) result = multiply(result, base, mod);
        base = multiply(base, base, mod);
        exponent >>= 1;
    }
    return result;
}

inline uint64_t integer_power(uint64_t base, int exponent) {
    uint64_t result = 1;
    for (int i = 0; i < exponent; i++) result *= base;
    return result;
}

inline uint64_t inverse(uint64_t value, uint64_t mod) {
    if (mod == 1) return 0;
    value %= mod;
    uint64_t old_remainder = mod;
    uint64_t remainder = value;
    __int128_t old_coefficient = 0;
    __int128_t coefficient = 1;
    while (remainder != 0) {
        const uint64_t quotient = old_remainder / remainder;
        const uint64_t next_remainder =
            old_remainder - quotient * remainder;
        old_remainder = remainder;
        remainder = next_remainder;

        const __int128_t next_coefficient =
            old_coefficient - static_cast<__int128_t>(quotient) * coefficient;
        old_coefficient = coefficient;
        coefficient = next_coefficient;
    }
    assert(old_remainder == 1);
    old_coefficient %= static_cast<__int128_t>(mod);
    if (old_coefficient < 0) old_coefficient += mod;
    return static_cast<uint64_t>(old_coefficient);
}

inline uint64_t extract_prime_power_root(
    uint64_t value,
    uint64_t root_prime,
    int exponent,
    uint64_t prime
) {
    uint64_t coprime_part = prime - 1;
    int available_exponent = 0;
    while (coprime_part % root_prime == 0) {
        coprime_part /= root_prime;
        available_exponent++;
    }
    assert(exponent <= available_exponent);

    const uint64_t root_prime_power = integer_power(root_prime, exponent);
    const uint64_t inverse_coprime_part = inverse(
        coprime_part, root_prime_power
    );
    const uint64_t residue = static_cast<uint64_t>(
        static_cast<__uint128_t>(root_prime_power - 1) *
        inverse_coprime_part % root_prime_power
    );
    const uint64_t root_exponent = static_cast<uint64_t>(
        (static_cast<__uint128_t>(residue) * coprime_part + 1) /
        root_prime_power
    );
    uint64_t root = power(value, root_exponent, prime);
    if (exponent == available_exponent) return root;

    uint64_t non_residue = 2;
    while (power(non_residue, (prime - 1) / root_prime, prime) == 1) {
        non_residue++;
    }
    const uint64_t generator = power(non_residue, coprime_part, prime);
    const uint64_t digit_generator = power(
        generator,
        integer_power(root_prime, available_exponent - 1),
        prime
    );

    const uint64_t step = isqrt(
        static_cast<uint64_t>(available_exponent - exponent) * root_prime
    ) + 1;
    const uint64_t giant_factor = power(digit_generator, step, prime);
    std::vector<std::pair<uint64_t, uint64_t>> baby_steps;
    baby_steps.reserve(step + 1);
    uint64_t current = 1;
    for (uint64_t index = 0; index <= step; index++) {
        baby_steps.emplace_back(current, index);
        current = multiply(current, giant_factor, prime);
    }
    std::sort(baby_steps.begin(), baby_steps.end());

    const uint64_t inverse_digit_generator = power(
        digit_generator, prime - 2, prime
    );
    for (int level = exponent; level < available_exponent; level++) {
        const uint64_t root_power = power(root, root_prime_power, prime);
        const uint64_t error = multiply(
            power(root_power, prime - 2, prime), value, prime
        );
        uint64_t target = power(
            error,
            integer_power(root_prime, available_exponent - 1 - level),
            prime
        );

        bool found = false;
        uint64_t logarithm = 0;
        for (uint64_t remainder = 0; remainder <= step; remainder++) {
            auto iterator = std::upper_bound(
                baby_steps.begin(),
                baby_steps.end(),
                target,
                [](uint64_t key, const std::pair<uint64_t, uint64_t>& entry) {
                    return key < entry.first;
                }
            );
            if (iterator != baby_steps.begin()) {
                --iterator;
                if (iterator->first == target) {
                    logarithm = remainder + step * iterator->second;
                    found = true;
                    break;
                }
            }
            target = multiply(target, inverse_digit_generator, prime);
        }
        assert(found);
        if (!found) return 0;

        const uint64_t correction_exponent =
            logarithm * integer_power(root_prime, level - exponent);
        root = multiply(
            root,
            power(generator, correction_exponent, prime),
            prime
        );
    }
    return root;
}

}  // namespace modular_kth_root_detail

// Returns x such that x^degree = value (mod prime), or nullopt when no root
// exists. The modulus must be prime.
inline std::optional<uint64_t> modular_kth_root(
    uint64_t value,
    uint64_t degree,
    uint64_t prime
) {
    assert(prime >= 2);
    value %= prime;
    if (degree == 0) {
        if (value == 1) return uint64_t(0);
        return std::nullopt;
    }
    if (value == 0) return uint64_t(0);
    if (prime == 2) return uint64_t(1);

    const uint64_t group_order = prime - 1;
    degree %= group_order;
    const uint64_t common_divisor = std::gcd(degree, group_order);
    if (
        modular_kth_root_detail::power(
            value, group_order / common_divisor, prime
        ) != 1
    ) {
        return std::nullopt;
    }

    const uint64_t reduced_order = group_order / common_divisor;
    uint64_t transformed = 1;
    if (reduced_order != 1) {
        const uint64_t inverse_degree = modular_kth_root_detail::inverse(
            degree / common_divisor, reduced_order
        );
        transformed = modular_kth_root_detail::power(
            value, inverse_degree, prime
        );
    }

    uint64_t remaining = common_divisor;
    int exponent = 0;
    while ((remaining & 1) == 0) {
        remaining >>= 1;
        exponent++;
    }
    if (exponent != 0) {
        transformed = modular_kth_root_detail::extract_prime_power_root(
            transformed, 2, exponent, prime
        );
    }
    for (uint64_t divisor = 3; divisor <= remaining / divisor; divisor += 2) {
        exponent = 0;
        while (remaining % divisor == 0) {
            remaining /= divisor;
            exponent++;
        }
        if (exponent != 0) {
            transformed = modular_kth_root_detail::extract_prime_power_root(
                transformed, divisor, exponent, prime
            );
        }
    }
    if (remaining != 1) {
        transformed = modular_kth_root_detail::extract_prime_power_root(
            transformed, remaining, 1, prime
        );
    }
    return transformed;
}

template <class Mint>
std::optional<Mint> modular_kth_root(Mint value, uint64_t degree) {
    auto root = modular_kth_root(
        static_cast<uint64_t>(value.val()),
        degree,
        static_cast<uint64_t>(Mint::mod())
    );
    if (!root.has_value()) return std::nullopt;
    return Mint(*root);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/multivariate_convolution.hpp"



#line 11 "math/multivariate_convolution.hpp"

#line 1 "math/primitive_root.hpp"



#line 9 "math/primitive_root.hpp"

#line 11 "math/primitive_root.hpp"

namespace m1une {
namespace math {

inline bool has_primitive_root(uint64_t mod) {
    if (mod == 2 || mod == 4) return true;
    if (mod < 2) return false;

    uint64_t odd_part = mod;
    if ((odd_part & 1) == 0) {
        odd_part >>= 1;
        if ((odd_part & 1) == 0) return false;
    }

    return prime_factorize(odd_part).size() == 1;
}

// Returns the smallest positive primitive root modulo mod.
// Returns 0 when no primitive root exists.
inline uint64_t primitive_root(uint64_t mod) {
    assert(mod >= 2);
    if (mod == 2) return 1;
    if (!has_primitive_root(mod)) return 0;

    const uint64_t phi = euler_phi(mod);
    const std::vector<std::pair<uint64_t, int>> factors = prime_factorize(phi);
    for (uint64_t candidate = 2; candidate < mod; candidate++) {
        if (std::gcd(candidate, mod) != 1) continue;

        bool generator = true;
        for (const auto& factor : factors) {
            if (internal::power_mod(candidate, phi / factor.first, mod) == 1) {
                generator = false;
                break;
            }
        }
        if (generator) return candidate;
    }
    return 0;
}

}  // namespace math
}  // namespace m1une


#line 14 "math/multivariate_convolution.hpp"

namespace m1une {
namespace math {

namespace internal {

template <class T>
struct nested_vector_traits {
    using scalar_type = T;
    static constexpr int depth = 0;
};

template <class T, class Allocator>
struct nested_vector_traits<std::vector<T, Allocator>> {
    using scalar_type = typename nested_vector_traits<T>::scalar_type;
    static constexpr int depth = nested_vector_traits<T>::depth + 1;
};

template <class Nested>
void nested_vector_shape(const Nested& values, std::vector<int>& shape) {
    if constexpr (nested_vector_traits<Nested>::depth > 0) {
        assert(!values.empty());
        assert(values.size() <= std::size_t(std::numeric_limits<int>::max()));
        shape.push_back(int(values.size()));
        nested_vector_shape(values.front(), shape);
    }
}

template <class Nested, class Mint>
void flatten_nested_vector(
    const Nested& values,
    const std::vector<int>& shape,
    int level,
    std::vector<Mint>& flattened
) {
    if constexpr (nested_vector_traits<Nested>::depth == 0) {
        flattened.push_back(values);
    } else {
        assert(level < int(shape.size()));
        assert(int(values.size()) == shape[level]);
        for (const auto& child : values) {
            flatten_nested_vector(child, shape, level + 1, flattened);
        }
    }
}

template <class Nested, class Mint>
void rebuild_nested_vector(
    Nested& values,
    const std::vector<int>& shape,
    int level,
    const std::vector<Mint>& flattened,
    int& position
) {
    if constexpr (nested_vector_traits<Nested>::depth == 0) {
        assert(position < int(flattened.size()));
        values = flattened[position++];
    } else {
        assert(level < int(shape.size()));
        values.resize(shape[level]);
        for (auto& child : values) {
            rebuild_nested_vector(child, shape, level + 1, flattened, position);
        }
    }
}

template <class Nested>
std::vector<int> flatten_multivariate_inputs(
    const Nested& first,
    const Nested& second,
    std::vector<typename nested_vector_traits<Nested>::scalar_type>& flattened_first,
    std::vector<typename nested_vector_traits<Nested>::scalar_type>& flattened_second
) {
    std::vector<int> shape;
    nested_vector_shape(first, shape);
    assert(int(shape.size()) == nested_vector_traits<Nested>::depth);

    std::vector<int> second_shape;
    nested_vector_shape(second, second_shape);
    assert(second_shape == shape);

    flatten_nested_vector(first, shape, 0, flattened_first);
    flatten_nested_vector(second, shape, 0, flattened_second);
    std::reverse(shape.begin(), shape.end());
    return shape;
}

template <class Nested>
Nested rebuild_multivariate_result(
    std::vector<int> dimensions,
    const std::vector<typename nested_vector_traits<Nested>::scalar_type>& flattened
) {
    std::reverse(dimensions.begin(), dimensions.end());
    Nested result;
    int position = 0;
    rebuild_nested_vector(result, dimensions, 0, flattened, position);
    assert(position == int(flattened.size()));
    return result;
}

inline int multivariate_coefficient_count(const std::vector<int>& dimensions) {
    int64_t count = 1;
    for (int dimension : dimensions) {
        assert(dimension > 0);
        count *= dimension;
        assert(count <= std::numeric_limits<int>::max());
    }
    return int(count);
}

inline std::vector<int> multivariate_colors(const std::vector<int>& dimensions) {
    const int variable_count = int(dimensions.size());
    const int coefficient_count = multivariate_coefficient_count(dimensions);
    std::vector<int> color(coefficient_count);
    if (variable_count == 0) return color;

    for (int index = 0; index < coefficient_count; index++) {
        int sum = 0;
        int stride = 1;
        for (int variable = 0; variable + 1 < variable_count; variable++) {
            stride *= dimensions[variable];
            sum += index / stride;
        }
        color[index] = sum % variable_count;
    }
    return color;
}

template <class Mint>
std::vector<Mint> geometric_evaluation(
    const std::vector<Mint>& polynomial, Mint ratio
) {
    const int size = int(polynomial.size());
    if (size <= 64) {
        std::vector<Mint> result(size);
        Mint point = 1;
        for (int i = 0; i < size; i++) {
            Mint power = 1;
            for (const Mint& coefficient : polynomial) {
                result[i] += coefficient * power;
                power *= point;
            }
            point *= ratio;
        }
        return result;
    }

    auto triangular_powers = [](Mint base, int length) {
        std::vector<Mint> result(length);
        if (length == 0) return result;
        result[0] = 1;
        Mint power = 1;
        for (int i = 0; i + 1 < length; i++) {
            result[i + 1] = result[i] * power;
            power *= base;
        }
        return result;
    };

    std::vector<Mint> positive = triangular_powers(ratio, 2 * size - 1);
    std::vector<Mint> negative = triangular_powers(ratio.inv(), size);
    std::vector<Mint> scaled(polynomial);
    for (int i = 0; i < size; i++) scaled[i] *= negative[i];
    std::reverse(scaled.begin(), scaled.end());
    std::vector<Mint> product = fps::convolution(scaled, positive);

    std::vector<Mint> result(size);
    for (int i = 0; i < size; i++) result[i] = product[size - 1 + i] * negative[i];
    return result;
}

template <class Mint>
std::vector<Mint> cyclic_fourier_transform(
    std::vector<Mint> values, Mint ratio, bool inverse
) {
    if constexpr (fps::internal::has_static_modulus<Mint>::value) {
        const int size = int(values.size());
        if ((size & (size - 1)) == 0) {
            // Keep normalization outside the per-axis transforms, matching
            // the arbitrary-length DFT path below.
            fps::internal::ntt(values, inverse, false);
            return values;
        }
    }
    return geometric_evaluation(values, ratio);
}

}  // namespace internal

template <class Mint>
std::vector<Mint> multivariate_convolution_truncated(
    const std::vector<int>& dimensions,
    const std::vector<Mint>& first,
    const std::vector<Mint>& second
) {
    static_assert(
        fps::internal::has_static_modulus<Mint>::value,
        "truncated multivariate convolution requires a static-modulus type"
    );
    const int variable_count = int(dimensions.size());
    const int coefficient_count = internal::multivariate_coefficient_count(dimensions);
    assert(int(first.size()) == coefficient_count);
    assert(int(second.size()) == coefficient_count);
    if (variable_count == 0) return {first[0] * second[0]};

    int64_t transform_size_64 = 1;
    while (transform_size_64 < 2LL * coefficient_count - 1) transform_size_64 <<= 1;
    assert(transform_size_64 <= std::numeric_limits<int>::max());
    const int transform_size = int(transform_size_64);
    assert((Mint::mod() - 1) % uint32_t(transform_size) == 0);

    const std::vector<int> color = internal::multivariate_colors(dimensions);
    std::vector<std::vector<Mint>> transformed_first(
        variable_count, std::vector<Mint>(transform_size)
    );
    std::vector<std::vector<Mint>> transformed_second(
        variable_count, std::vector<Mint>(transform_size)
    );
    for (int i = 0; i < coefficient_count; i++) {
        transformed_first[color[i]][i] = first[i];
        transformed_second[color[i]][i] = second[i];
    }
    for (int group = 0; group < variable_count; group++) {
        fps::internal::ntt(transformed_first[group], false);
        fps::internal::ntt(transformed_second[group], false);
    }

    std::vector<std::vector<Mint>> transformed_result(
        variable_count, std::vector<Mint>(transform_size)
    );
    for (int left = 0; left < variable_count; left++) {
        for (int right = 0; right < variable_count; right++) {
            std::vector<Mint>& destination =
                transformed_result[(left + right) % variable_count];
            const std::vector<Mint>& left_values = transformed_first[left];
            const std::vector<Mint>& right_values = transformed_second[right];
            for (int i = 0; i < transform_size; i++) {
                destination[i] += left_values[i] * right_values[i];
            }
        }
    }
    for (int group = 0; group < variable_count; group++) {
        fps::internal::ntt(transformed_result[group], true);
    }

    std::vector<Mint> result(coefficient_count);
    for (int i = 0; i < coefficient_count; i++) {
        result[i] = transformed_result[color[i]][i];
    }
    return result;
}

template <
    class Nested,
    std::enable_if_t<(internal::nested_vector_traits<Nested>::depth > 0), int> = 0
>
Nested multivariate_convolution_truncated(
    const Nested& first,
    const Nested& second
) {
    using Mint = typename internal::nested_vector_traits<Nested>::scalar_type;
    std::vector<Mint> flattened_first, flattened_second;
    std::vector<int> dimensions = internal::flatten_multivariate_inputs(
        first, second, flattened_first, flattened_second
    );
    std::vector<Mint> flattened_result = multivariate_convolution_truncated(
        dimensions, flattened_first, flattened_second
    );
    return internal::rebuild_multivariate_result<Nested>(
        std::move(dimensions), flattened_result
    );
}

template <class Mint>
std::vector<Mint> multivariate_convolution_cyclic(
    const std::vector<int>& dimensions,
    const std::vector<Mint>& first,
    const std::vector<Mint>& second
) {
    const int coefficient_count = internal::multivariate_coefficient_count(dimensions);
    assert(int(first.size()) == coefficient_count);
    assert(int(second.size()) == coefficient_count);
    if (dimensions.empty()) return {first[0] * second[0]};

    const uint32_t modulus = Mint::mod();
    bool has_all_roots = true;
    for (int dimension : dimensions) {
        if ((modulus - 1) % uint32_t(dimension) != 0) has_all_roots = false;
    }
    if (!has_all_roots) {
        std::vector<int> reduced_dimensions;
        for (int dimension : dimensions) {
            if (dimension != 1) reduced_dimensions.push_back(dimension);
        }
        if (reduced_dimensions.empty()) return {first[0] * second[0]};

        std::vector<int> widened_dimensions(reduced_dimensions.size());
        for (int i = 0; i < int(reduced_dimensions.size()); i++) {
            const int64_t widened = 2LL * reduced_dimensions[i] - 1;
            assert(widened <= std::numeric_limits<int>::max());
            widened_dimensions[i] = int(widened);
        }
        const int widened_count =
            internal::multivariate_coefficient_count(widened_dimensions);

        // The largest embedded input index uses coordinate dimension - 1 on
        // every axis.  Its double is widened_count - 1, so convolving arrays
        // ending at this index produces exactly the widened mixed-radix box.
        // In particular, fps::convolution chooses the smallest transform that
        // contains widened_count coefficients, instead of one that contains
        // 2 * widened_count - 1 coefficients due to trailing zeroes.
        int64_t maximum_embedded_index = 0;
        int64_t widened_stride = 1;
        for (int variable = 0; variable < int(reduced_dimensions.size()); variable++) {
            maximum_embedded_index +=
                int64_t(reduced_dimensions[variable] - 1) * widened_stride;
            widened_stride *= widened_dimensions[variable];
        }
        assert(widened_stride == widened_count);
        assert(2 * maximum_embedded_index + 1 == widened_count);
        assert(maximum_embedded_index < std::numeric_limits<int>::max());
        const int embedded_input_count = int(maximum_embedded_index) + 1;
        std::vector<Mint> widened_first(embedded_input_count);
        std::vector<Mint> widened_second(embedded_input_count);
        for (int index = 0; index < coefficient_count; index++) {
            int remaining = index;
            int widened_index = 0;
            int embedding_stride = 1;
            for (int variable = 0; variable < int(reduced_dimensions.size()); variable++) {
                const int coordinate = remaining % reduced_dimensions[variable];
                remaining /= reduced_dimensions[variable];
                widened_index += coordinate * embedding_stride;
                embedding_stride *= widened_dimensions[variable];
            }
            widened_first[widened_index] = first[index];
            widened_second[widened_index] = second[index];
        }

        std::vector<Mint> widened_product =
            fps::convolution(widened_first, widened_second);
        assert(int(widened_product.size()) == widened_count);
        std::vector<Mint> result(coefficient_count);
        for (int widened_index = 0; widened_index < widened_count; widened_index++) {
            int remaining = widened_index;
            int index = 0;
            int stride = 1;
            for (int variable = 0; variable < int(reduced_dimensions.size()); variable++) {
                const int coordinate = remaining % widened_dimensions[variable];
                remaining /= widened_dimensions[variable];
                index += (coordinate % reduced_dimensions[variable]) * stride;
                stride *= reduced_dimensions[variable];
            }
            result[index] += widened_product[widened_index];
        }
        return result;
    }

    const uint64_t generator = primitive_root(modulus);
    assert(generator != 0);

    std::vector<Mint> transformed_first(first);
    std::vector<Mint> transformed_second(second);
    int stride = 1;
    for (int dimension : dimensions) {
        assert((modulus - 1) % uint32_t(dimension) == 0);
        const Mint root = Mint(generator).pow((modulus - 1) / dimension);
        for (int block = 0; block < coefficient_count; block += stride * dimension) {
            for (int offset = 0; offset < stride; offset++) {
                std::vector<Mint> first_line(dimension);
                std::vector<Mint> second_line(dimension);
                for (int i = 0; i < dimension; i++) {
                    first_line[i] = transformed_first[block + offset + stride * i];
                    second_line[i] = transformed_second[block + offset + stride * i];
                }
                first_line = internal::cyclic_fourier_transform(
                    std::move(first_line), root, false
                );
                second_line = internal::cyclic_fourier_transform(
                    std::move(second_line), root, false
                );
                for (int i = 0; i < dimension; i++) {
                    transformed_first[block + offset + stride * i] = first_line[i];
                    transformed_second[block + offset + stride * i] = second_line[i];
                }
            }
        }
        stride *= dimension;
    }

    for (int i = 0; i < coefficient_count; i++) {
        transformed_first[i] *= transformed_second[i];
    }

    stride = 1;
    for (int dimension : dimensions) {
        const Mint inverse_root =
            Mint(generator).pow((modulus - 1) / dimension).inv();
        for (int block = 0; block < coefficient_count; block += stride * dimension) {
            for (int offset = 0; offset < stride; offset++) {
                std::vector<Mint> line(dimension);
                for (int i = 0; i < dimension; i++) {
                    line[i] = transformed_first[block + offset + stride * i];
                }
                line = internal::cyclic_fourier_transform(
                    std::move(line), inverse_root, true
                );
                for (int i = 0; i < dimension; i++) {
                    transformed_first[block + offset + stride * i] = line[i];
                }
            }
        }
        stride *= dimension;
    }

    const Mint inverse_size = Mint(coefficient_count).inv();
    for (Mint& value : transformed_first) value *= inverse_size;
    return transformed_first;
}

template <
    class Nested,
    std::enable_if_t<(internal::nested_vector_traits<Nested>::depth > 0), int> = 0
>
Nested multivariate_convolution_cyclic(
    const Nested& first,
    const Nested& second
) {
    using Mint = typename internal::nested_vector_traits<Nested>::scalar_type;
    std::vector<Mint> flattened_first, flattened_second;
    std::vector<int> dimensions = internal::flatten_multivariate_inputs(
        first, second, flattened_first, flattened_second
    );
    std::vector<Mint> flattened_result = multivariate_convolution_cyclic(
        dimensions, flattened_first, flattened_second
    );
    return internal::rebuild_multivariate_result<Nested>(
        std::move(dimensions), flattened_result
    );
}

}  // namespace math
}  // namespace m1une


#line 1 "math/multiplicative_function_prefix_sum.hpp"



#line 11 "math/multiplicative_function_prefix_sum.hpp"

namespace m1une {
namespace math {

// Computes summatory multiplicative functions with a Min_25 sieve.
// prime_power(p, e) must return f(p^e), and prime_prefix must contain
// sum_{p <= x} f(p) at every x represented by quotient_values().
template <class T, class PrimePower>
struct MultiplicativeFunctionPrefixSum {
   private:
    uint64_t _n;
    uint64_t _sqrt_n;
    uint64_t _large_size;
    std::vector<int> _primes;
    PrimePower _prime_power;

    static uint64_t integer_sqrt(uint64_t n) {
        uint64_t result = static_cast<uint64_t>(std::sqrt(static_cast<long double>(n)));
        while (result != 0 && result > n / result) result--;
        while (result + 1 <= n / (result + 1)) result++;
        return result;
    }

    static uint64_t validated_sqrt(uint64_t n) {
        const uint64_t result = integer_sqrt(n);
        assert(result <= static_cast<uint64_t>(std::numeric_limits<int>::max() / 2));
        return result;
    }

    static std::vector<int> enumerate_primes(uint64_t limit) {
        assert(limit <= static_cast<uint64_t>(std::numeric_limits<int>::max()));
        const int n = static_cast<int>(limit);
        std::vector<bool> is_composite(n + 1);
        std::vector<int> primes;
        for (int value = 2; value <= n; value++) {
            if (!is_composite[value]) primes.push_back(value);
            for (int prime : primes) {
                if (value > n / prime) break;
                is_composite[value * prime] = true;
                if (value % prime == 0) break;
            }
        }
        return primes;
    }

    T triangular(uint64_t n) const {
        if ((n & 1) == 0) return T(n / 2) * T(n + 1);
        return T(n) * T((n + 1) / 2);
    }

   public:
    explicit MultiplicativeFunctionPrefixSum(uint64_t n, PrimePower prime_power)
        : _n(n),
          _sqrt_n(validated_sqrt(n)),
          _large_size(n == 0 ? 0 : n / _sqrt_n),
          _primes(enumerate_primes(_sqrt_n)),
          _prime_power(std::move(prime_power)) {
        if (n == 0) return;
        while (_large_size > 1 && n / (_large_size - 1) == _sqrt_n) _large_size--;
    }

    uint64_t n() const {
        return _n;
    }

    uint64_t sqrt_n() const {
        return _sqrt_n;
    }

    const std::vector<int>& primes() const {
        return _primes;
    }

    int table_size() const {
        if (_n == 0) return 0;
        return static_cast<int>(_large_size + _sqrt_n);
    }

    // Returns the table index representing x. The argument must be one of the
    // values returned by quotient_values().
    int index(uint64_t x) const {
        assert(_n > 0 && 1 <= x && x <= _n);
        if (x <= _sqrt_n) return table_size() - static_cast<int>(x);
        const uint64_t result = _n / x;
        assert(result < _large_size);
        return static_cast<int>(result);
    }

    // table[i] represents the value at quotient_values()[i]. Index zero is a
    // dummy entry; the represented values occupy indices [1, table_size()).
    std::vector<uint64_t> quotient_values() const {
        if (_n == 0) return {};
        std::vector<uint64_t> result(table_size());
        for (uint64_t i = 1; i < _large_size; i++) result[i] = _n / i;
        for (uint64_t value = 1; value <= _sqrt_n; value++) {
            result[index(value)] = value;
        }
        return result;
    }

    // Returns pi(x) at every represented x.
    std::vector<T> prime_count_table() const {
        if (_n == 0) return {};
        std::vector<uint64_t> large(_large_size);
        for (uint64_t i = 1; i < _large_size; i++) large[i] = _n / i - 1;

        std::vector<uint64_t> small(_sqrt_n + 1);
        for (uint64_t value = 1; value <= _sqrt_n; value++) small[value] = value - 1;

        uint64_t prime_count = 0;
        for (int prime_int : _primes) {
            const uint64_t prime = static_cast<uint64_t>(prime_int);
            const uint64_t square = prime * prime;
            const uint64_t end = std::min(_large_size, _n / square + 1);
            uint64_t product = prime;
            for (uint64_t i = 1; i < end; i++, product += prime) {
                const uint64_t previous = product < _large_size ? large[product] : small[_n / product];
                large[i] -= previous - prime_count;
            }
            for (uint64_t value = _sqrt_n; value >= square; value--) {
                small[value] -= small[value / prime] - prime_count;
            }
            prime_count++;
        }

        std::vector<T> result(table_size());
        for (uint64_t i = 0; i < _large_size; i++) result[i] = T(large[i]);
        for (uint64_t value = 1; value <= _sqrt_n; value++) result[index(value)] = T(small[value]);
        return result;
    }

    // Returns sum_{p <= x} p at every represented x.
    std::vector<T> prime_sum_table() const {
        if (_n == 0) return {};
        std::vector<T> result(table_size());
        for (uint64_t i = 1; i < _large_size; i++) result[i] = triangular(_n / i) - T(1);
        for (uint64_t value = 1; value <= _sqrt_n; value++) {
            result[index(value)] = triangular(value) - T(1);
        }

        for (int prime_int : _primes) {
            const uint64_t prime = static_cast<uint64_t>(prime_int);
            const uint64_t square = prime * prime;
            const T before = result[index(prime - 1)];
            const uint64_t end = std::min(_large_size, _n / square + 1);
            uint64_t product = prime;
            for (uint64_t i = 1; i < end; i++, product += prime) {
                result[i] -= (result[index(_n / product)] - before) * T(prime);
            }
            for (uint64_t value = _sqrt_n; value >= square; value--) {
                result[index(value)] -= (result[index(value / prime)] - before) * T(prime);
            }
        }
        return result;
    }

    // Returns sum_{k=1}^x f(k) at every represented x.
    std::vector<T> prefix_sum_table(const std::vector<T>& prime_prefix) const {
        if (_n == 0) {
            assert(prime_prefix.empty());
            return {};
        }
        assert(static_cast<int>(prime_prefix.size()) == table_size());

        const std::vector<uint64_t> values = quotient_values();
        std::vector<T> result = prime_prefix;
        std::vector<T> next = prime_prefix;
        for (int prime_index = static_cast<int>(_primes.size()) - 1; prime_index >= 0; prime_index--) {
            const uint64_t prime = static_cast<uint64_t>(_primes[prime_index]);
            uint64_t power = prime;
            int exponent = 1;
            while (power <= _n / prime) {
                const T current_value = _prime_power(prime, exponent);
                const T next_value = _prime_power(prime, exponent + 1);
                const T primes_before = prime_prefix[index(prime)];
                for (int i = 1; i < table_size(); i++) {
                    const uint64_t value = values[i];
                    if (value < power * prime) break;
                    next[i] += current_value * (result[index(value / power)] - primes_before) + next_value;
                }
                exponent++;
                power *= prime;
            }
            const uint64_t bound = prime * prime;
            const int copy_size = std::min(table_size(), index(bound) + 1);
            std::copy(next.begin(), next.begin() + copy_size, result.begin());
        }
        for (int i = 1; i < table_size(); i++) result[i] += T(1);
        return result;
    }

    T prefix_sum(const std::vector<T>& prime_prefix) const {
        if (_n == 0) {
            assert(prime_prefix.empty());
            return T{};
        }
        return prefix_sum_table(prime_prefix)[index(_n)];
    }
};

}  // namespace math
}  // namespace m1une


#line 1 "math/prefix_sum_of_binom.hpp"



#line 11 "math/prefix_sum_of_binom.hpp"

#line 13 "math/prefix_sum_of_binom.hpp"

namespace m1une {
namespace math {

// Answers sum_{k=0}^{m-1} binom(n, k) after square-root decomposition.
template <class Mint>
struct PrefixSumOfBinom {
   private:
    int _maximum;
    int _block_size;
    Combinatorics<Mint> _combinations;
    std::vector<Mint> _powers_of_two;
    std::vector<std::vector<Mint>> _data;

    Mint _block_prefix(int n, int block) const {
        const int endpoint = block * _block_size;
        if (n <= endpoint) return _powers_of_two[n];
        return _data[block][n - endpoint] * _combinations.inverse_factorial(endpoint);
    }

    Mint _binom_sum(int n, int left, int right) const {
        __uint128_t sum = 0;
        for (int k = left; k < right; k++) {
            sum += static_cast<__uint128_t>(_combinations.inverse_factorial(k).val()) *
                   _combinations.inverse_factorial(n - k).val();
        }
        const uint32_t reduced = static_cast<uint32_t>(sum % Mint::mod());
        return Mint::raw(reduced) * _combinations.factorial(n);
    }

   public:
    explicit PrefixSumOfBinom(int maximum)
        : _maximum(maximum),
          _block_size(std::max(1, int(std::sqrt(static_cast<double>(maximum) + 1)))),
          _combinations(maximum),
          _powers_of_two(maximum + 1, Mint(1)) {
        assert(maximum >= 0);

        for (int n = 0; n < maximum; n++) {
            _powers_of_two[n + 1] = _powers_of_two[n] + _powers_of_two[n];
        }

        const int block_count = maximum / (2 * _block_size) + 3;
        _data.resize(block_count);
        for (int block = 0; block < block_count; block++) {
            const int endpoint = block * _block_size;
            if (endpoint > maximum) continue;

            std::vector<Mint>& values = _data[block];
            values.resize(maximum - endpoint + 1);
            values[0] = _powers_of_two[endpoint] * _combinations.factorial(endpoint);
            for (int offset = 0; offset < maximum - endpoint; offset++) {
                values[offset + 1] =
                    values[offset] + values[offset] -
                    _combinations.factorial(offset + endpoint) *
                        _combinations.inverse_factorial(offset);
            }
        }
    }

    int maximum() const {
        return _maximum;
    }

    // Returns sum_{k=0}^{m-1} binom(n, k). Values m > n + 1 are clamped.
    Mint query(int n, int m) const {
        assert(0 <= n && n <= _maximum);
        assert(m >= 0);
        m = std::min(m, n + 1);
        if (m == 0) return Mint(0);
        if (2 * m > n + 1) {
            return _powers_of_two[n] - query(n, n + 1 - m);
        }

        const int endpoint = m - 1;
        const int block = endpoint / _block_size;
        const int lower = block * _block_size;
        const int upper = (block + 1) * _block_size;
        if (endpoint - lower <= upper - endpoint) {
            return _block_prefix(n, block) + _binom_sum(n, lower + 1, endpoint + 1);
        }
        return _block_prefix(n, block + 1) - _binom_sum(n, endpoint + 1, upper + 1);
    }
};

// Batches the same queries and evaluates them in Mo order with linear memory.
template <class Mint>
struct OfflinePrefixSumOfBinom {
   private:
    std::vector<std::pair<int, int>> _queries;

   public:
    int query_count() const {
        return int(_queries.size());
    }

    bool empty() const {
        return _queries.empty();
    }

    void reserve(int query_capacity) {
        assert(query_capacity >= 0);
        _queries.reserve(query_capacity);
    }

    void clear() {
        _queries.clear();
    }

    // Adds sum_{k=0}^{m-1} binom(n, k) and returns its insertion-order ID.
    int add_query(int n, int m) {
        assert(n >= 0);
        assert(m >= 0);
        m = std::min(m, n + 1);
        const int id = query_count();
        _queries.emplace_back(n, m);
        return id;
    }

    std::vector<Mint> calculate() const {
        const int count = query_count();
        std::vector<Mint> answers(count);
        if (count == 0) return answers;

        int maximum = 0;
        for (const auto& query : _queries) maximum = std::max(maximum, query.first);
        assert(static_cast<uint64_t>(maximum) < Mint::mod());
        assert(Mint::mod() % 2 == 1);
        Combinatorics<Mint> combinations(maximum);

        const int block_size =
            std::max(1, int(maximum / std::sqrt(static_cast<double>(count))));
        std::vector<int> order(count);
        std::iota(order.begin(), order.end(), 0);
        std::sort(order.begin(), order.end(), [&](int first, int second) {
            const int first_block = _queries[first].first / block_size;
            const int second_block = _queries[second].first / block_size;
            if (first_block != second_block) return first_block < second_block;
            if (first_block & 1) return _queries[first].second > _queries[second].second;
            return _queries[first].second < _queries[second].second;
        });

        int n = 0;
        int m = 0;
        Mint answer = 0;
        const Mint inverse_two = Mint(2).inv();
        for (int id : order) {
            const int next_n = _queries[id].first;
            const int next_m = _queries[id].second;
            while (n < next_n) {
                answer += answer;
                answer -= combinations.binom(n, m - 1);
                n++;
            }
            while (n > next_n) {
                answer += combinations.binom(n - 1, m - 1);
                answer *= inverse_two;
                n--;
            }
            while (m < next_m) answer += combinations.binom(n, m++);
            while (m > next_m) answer -= combinations.binom(n, --m);
            answers[id] = answer;
        }
        return answers;
    }
};

}  // namespace math
}  // namespace m1une


#line 1 "math/prime_sieve.hpp"



#line 8 "math/prime_sieve.hpp"

namespace m1une {
namespace math {

struct PrimeSieve {
   private:
    int _limit;
    std::vector<int> _min_prime_factor;
    std::vector<int> _primes;

   public:
    explicit PrimeSieve(int limit = 0) : _limit(0) {
        assert(limit >= 0);
        _limit = limit;
        _min_prime_factor.assign(limit + 1, 0);
        if (limit >= 1) _min_prime_factor[1] = 1;
        for (int value = 2; value <= limit; value++) {
            if (_min_prime_factor[value] == 0) {
                _min_prime_factor[value] = value;
                _primes.push_back(value);
            }
            for (int prime : _primes) {
                if (prime > _min_prime_factor[value] || value > limit / prime) break;
                _min_prime_factor[value * prime] = prime;
            }
        }
    }

    int limit() const {
        return _limit;
    }

    const std::vector<int>& primes() const {
        return _primes;
    }

    const std::vector<int>& min_prime_factors() const {
        return _min_prime_factor;
    }

    bool is_prime(int value) const {
        assert(0 <= value && value <= _limit);
        return value >= 2 && _min_prime_factor[value] == value;
    }

    int min_prime_factor(int value) const {
        assert(2 <= value && value <= _limit);
        return _min_prime_factor[value];
    }

    std::vector<std::pair<int, int>> factorize(int value) const {
        assert(1 <= value && value <= _limit);
        std::vector<std::pair<int, int>> result;
        while (value > 1) {
            const int prime = _min_prime_factor[value];
            int exponent = 0;
            do {
                value /= prime;
                exponent++;
            } while (value > 1 && _min_prime_factor[value] == prime);
            result.emplace_back(prime, exponent);
        }
        return result;
    }

    std::vector<int> divisors(int value) const {
        std::vector<int> result = {1};
        for (const auto& factor : factorize(value)) {
            const int current_size = int(result.size());
            int power = 1;
            for (int exponent = 1; exponent <= factor.second; exponent++) {
                power *= factor.first;
                for (int i = 0; i < current_size; i++) {
                    result.push_back(result[i] * power);
                }
            }
        }
        std::sort(result.begin(), result.end());
        return result;
    }

    int totient(int value) const {
        assert(1 <= value && value <= _limit);
        int result = value;
        for (const auto& factor : factorize(value)) {
            result = result / factor.first * (factor.first - 1);
        }
        return result;
    }

    int mobius(int value) const {
        assert(1 <= value && value <= _limit);
        int result = 1;
        for (const auto& factor : factorize(value)) {
            if (factor.second >= 2) return 0;
            result = -result;
        }
        return result;
    }

    std::vector<int> totient_table() const {
        std::vector<int> result(_limit + 1);
        if (_limit >= 1) result[1] = 1;
        for (int value = 2; value <= _limit; value++) {
            const int prime = _min_prime_factor[value];
            const int reduced = value / prime;
            result[value] = reduced % prime == 0 ? result[reduced] * prime : result[reduced] * (prime - 1);
        }
        return result;
    }

    std::vector<int> mobius_table() const {
        std::vector<int> result(_limit + 1);
        if (_limit >= 1) result[1] = 1;
        for (int value = 2; value <= _limit; value++) {
            const int prime = _min_prime_factor[value];
            const int reduced = value / prime;
            result[value] = reduced % prime == 0 ? 0 : -result[reduced];
        }
        return result;
    }
};

}  // namespace math
}  // namespace m1une


#line 1 "math/rational.hpp"



#line 7 "math/rational.hpp"
#include <compare>
#line 11 "math/rational.hpp"
#include <sstream>
#line 15 "math/rational.hpp"

namespace m1une {
namespace math {

namespace rational_detail {

template <class T>
concept IntegerLike =
    std::signed_integral<T> ||
    (!std::integral<T> && std::copyable<T> && requires(T first, T second) {
        T(0);
        T(1);
        { -first } -> std::same_as<T>;
        { first + second } -> std::same_as<T>;
        { first - second } -> std::same_as<T>;
        { first * second } -> std::same_as<T>;
        { first / second } -> std::same_as<T>;
        { first % second } -> std::same_as<T>;
        { first += second } -> std::same_as<T&>;
        { first -= second } -> std::same_as<T&>;
        { first /= second } -> std::same_as<T&>;
        { first == second } -> std::convertible_to<bool>;
        { first < second } -> std::convertible_to<bool>;
    });

}  // namespace rational_detail

template <rational_detail::IntegerLike T = long long>
struct Rational {
    static_assert(!std::signed_integral<T> || sizeof(T) <= sizeof(long long));

   private:
    static constexpr bool BUILTIN_INTEGER = std::signed_integral<T>;
    using Wide = std::conditional_t<BUILTIN_INTEGER, __int128_t, T>;
    using Magnitude = std::conditional_t<BUILTIN_INTEGER, __uint128_t, T>;

    T _numerator;
    T _denominator;

    static constexpr Magnitude magnitude(Wide value) {
        if constexpr (BUILTIN_INTEGER) {
            if (value < 0) {
                return static_cast<Magnitude>(-(value + 1)) + 1;
            }
            return static_cast<Magnitude>(value);
        } else {
            return value < 0 ? -value : value;
        }
    }

    static constexpr Magnitude gcd(Magnitude first, Magnitude second) {
        while (second != 0) {
            Magnitude remainder = first % second;
            first = second;
            second = remainder;
        }
        return first;
    }

    static constexpr T narrow(Wide value) {
        if constexpr (BUILTIN_INTEGER) {
            assert(Wide(std::numeric_limits<T>::min()) <= value);
            assert(value <= Wide(std::numeric_limits<T>::max()));
            return static_cast<T>(value);
        } else {
            return value;
        }
    }

    constexpr void assign_normalized(Wide numerator, Wide denominator) {
        assert(denominator != 0);
        if (numerator == 0) {
            _numerator = 0;
            _denominator = 1;
            return;
        }

        Magnitude divisor = gcd(magnitude(numerator), magnitude(denominator));
        numerator /= static_cast<Wide>(divisor);
        denominator /= static_cast<Wide>(divisor);
        if (denominator < 0) {
            numerator = -numerator;
            denominator = -denominator;
        }
        _numerator = narrow(numerator);
        _denominator = narrow(denominator);
    }

    static constexpr Rational from_wide(Wide numerator, Wide denominator) {
        Rational result;
        result.assign_normalized(numerator, denominator);
        return result;
    }

    static std::pair<long double, long long> decimal_scientific(const T& value) {
        std::ostringstream output;
        output << value;
        const std::string text = output.str();
        std::size_t begin = 0;
        int sign = 1;
        if (!text.empty() && (text[0] == '-' || text[0] == '+')) {
            if (text[0] == '-') sign = -1;
            begin = 1;
        }
        while (begin < text.size() && text[begin] == '0') ++begin;
        if (begin == text.size()) return std::make_pair(0.0L, 0LL);

        constexpr int DIGITS = std::numeric_limits<long double>::digits10 + 1;
        const std::size_t used = std::min<std::size_t>(DIGITS, text.size() - begin);
        long double significand = 0;
        for (std::size_t i = 0; i < used; ++i) {
            assert('0' <= text[begin + i] && text[begin + i] <= '9');
            significand = significand * 10 + (text[begin + i] - '0');
        }
        for (std::size_t i = 1; i < used; ++i) significand /= 10;
        const long long exponent = static_cast<long long>(text.size() - begin - 1);
        return std::make_pair(sign * significand, exponent);
    }

   public:
    constexpr Rational() : _numerator(0), _denominator(1) {}

    constexpr Rational(T integer) : _numerator(integer), _denominator(1) {}

    template <std::integral U>
        requires std::constructible_from<T, U> &&
                 (!std::same_as<std::remove_cv_t<U>, T>)
    constexpr Rational(U integer) : Rational(T(integer)) {}

    constexpr Rational(T numerator, T denominator) {
        assign_normalized(Wide(numerator), Wide(denominator));
    }

    constexpr T numerator() const {
        return _numerator;
    }

    constexpr T denominator() const {
        return _denominator;
    }

    constexpr bool is_integer() const {
        return _denominator == 1;
    }

    constexpr int sign() const {
        return (_numerator > 0) - (_numerator < 0);
    }

    constexpr Rational reciprocal() const {
        assert(_numerator != 0);
        return from_wide(Wide(_denominator), Wide(_numerator));
    }

    constexpr Rational abs() const {
        return _numerator < 0 ? -*this : *this;
    }

    constexpr long double to_long_double() const
        requires requires(const T& value) { static_cast<long double>(value); }
    {
        return static_cast<long double>(_numerator) / static_cast<long double>(_denominator);
    }

    long double to_long_double() const
        requires(!requires(const T& value) { static_cast<long double>(value); })
    {
        const auto [numerator, numerator_exponent] = decimal_scientific(_numerator);
        const auto [denominator, denominator_exponent] = decimal_scientific(_denominator);
        return numerator / denominator *
               std::pow(10.0L, numerator_exponent - denominator_exponent);
    }

    template <std::floating_point F>
    explicit constexpr operator F() const
        requires requires(const T& value) { static_cast<long double>(value); }
    {
        return static_cast<F>(to_long_double());
    }

    template <std::floating_point F>
    explicit operator F() const
        requires(!requires(const T& value) { static_cast<long double>(value); })
    {
        return static_cast<F>(to_long_double());
    }

    constexpr T trunc() const {
        return _numerator / _denominator;
    }

    constexpr T floor() const {
        T quotient = _numerator / _denominator;
        if (_numerator < 0 && _numerator % _denominator != 0) quotient -= T(1);
        return quotient;
    }

    constexpr T ceil() const {
        T quotient = _numerator / _denominator;
        if (0 < _numerator && _numerator % _denominator != 0) quotient += T(1);
        return quotient;
    }

    constexpr Rational operator+() const {
        return *this;
    }

    constexpr Rational operator-() const {
        return from_wide(-Wide(_numerator), Wide(_denominator));
    }

    constexpr Rational& operator+=(const Rational& other) {
        Magnitude common =
            gcd(static_cast<Magnitude>(_denominator), static_cast<Magnitude>(other._denominator));
        Wide left_scale = Wide(other._denominator) / static_cast<Wide>(common);
        Wide right_scale = Wide(_denominator) / static_cast<Wide>(common);
        Wide numerator =
            Wide(_numerator) * left_scale + Wide(other._numerator) * right_scale;

        // With both operands already reduced, every factor shared by the new
        // numerator and denominator must divide `common`.  Restricting the
        // second gcd to that value avoids a full-size gcd against the product
        // of both denominators, which is especially important for BigInt.
        Magnitude reduction = common == Magnitude(1)
                                  ? Magnitude(1)
                                  : gcd(magnitude(numerator), common);
        if (reduction != Magnitude(1)) {
            numerator /= static_cast<Wide>(reduction);
        }
        Wide remaining_denominator = Wide(other._denominator);
        if (reduction != Magnitude(1)) {
            remaining_denominator /= static_cast<Wide>(reduction);
        }
        _numerator = narrow(numerator);
        _denominator = narrow(right_scale * remaining_denominator);
        return *this;
    }

    constexpr Rational& operator-=(const Rational& other) {
        return *this += -other;
    }

    constexpr Rational& operator*=(const Rational& other) {
        Magnitude first_gcd = gcd(magnitude(Wide(_numerator)), static_cast<Magnitude>(other._denominator));
        Magnitude second_gcd = gcd(magnitude(Wide(other._numerator)), static_cast<Magnitude>(_denominator));
        assign_normalized((Wide(_numerator) / static_cast<Wide>(first_gcd)) *
                              (Wide(other._numerator) / static_cast<Wide>(second_gcd)),
                          (Wide(_denominator) / static_cast<Wide>(second_gcd)) *
                              (Wide(other._denominator) / static_cast<Wide>(first_gcd)));
        return *this;
    }

    constexpr Rational& operator/=(const Rational& other) {
        return *this *= other.reciprocal();
    }

    friend constexpr Rational operator+(Rational left, const Rational& right) {
        return left += right;
    }

    friend constexpr Rational operator-(Rational left, const Rational& right) {
        return left -= right;
    }

    friend constexpr Rational operator*(Rational left, const Rational& right) {
        return left *= right;
    }

    friend constexpr Rational operator/(Rational left, const Rational& right) {
        return left /= right;
    }

    friend constexpr bool operator==(const Rational& left, const Rational& right) {
        return left._numerator == right._numerator && left._denominator == right._denominator;
    }

    friend constexpr std::strong_ordering operator<=>(const Rational& left, const Rational& right) {
        Wide first = Wide(left._numerator) * Wide(right._denominator);
        Wide second = Wide(right._numerator) * Wide(left._denominator);
        if (first < second) return std::strong_ordering::less;
        if (second < first) return std::strong_ordering::greater;
        return std::strong_ordering::equal;
    }

    friend std::ostream& operator<<(std::ostream& output, const Rational& value) {
        output << value._numerator;
        if (value._denominator != 1) {
            output << '/' << value._denominator;
        }
        return output;
    }

    friend std::istream& operator>>(std::istream& input, Rational& value) {
        std::string token;
        if (!(input >> token)) return input;

        std::size_t slash = token.find('/');
        if (slash != std::string::npos && token.find('/', slash + 1) != std::string::npos) {
            input.setstate(std::ios::failbit);
            return input;
        }

        T numerator = 0;
        T denominator = 1;
        std::istringstream numerator_input(token.substr(0, slash));
        if (!(numerator_input >> numerator) || numerator_input.peek() != std::char_traits<char>::eof()) {
            input.setstate(std::ios::failbit);
            return input;
        }
        if (slash != std::string::npos) {
            std::istringstream denominator_input(token.substr(slash + 1));
            if (!(denominator_input >> denominator) ||
                denominator_input.peek() != std::char_traits<char>::eof()) {
                input.setstate(std::ios::failbit);
                return input;
            }
        }
        value = Rational(numerator, denominator);
        return input;
    }
};

template <rational_detail::IntegerLike T>
constexpr Rational<T> abs(const Rational<T>& value) {
    return value.abs();
}

}  // namespace math
}  // namespace m1une

namespace std {

// Integer/rational common types already follow from implicit integer
// construction. Mixing a floating scalar explicitly chooses approximation.
template <m1une::math::rational_detail::IntegerLike T, floating_point F>
struct common_type<m1une::math::Rational<T>, F> {
    using type = long double;
};

template <floating_point F, m1une::math::rational_detail::IntegerLike T>
struct common_type<F, m1une::math::Rational<T>> {
    using type = long double;
};

}  // namespace std


#line 1 "math/rational_approximation.hpp"



#line 10 "math/rational_approximation.hpp"

namespace m1une {
namespace math {

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
struct RationalApproximationResult {
    using fraction_type = std::pair<T, T>;

    fraction_type lower;
    fraction_type upper;
};

namespace rational_approximation_detail {

using Wide = __uint128_t;

struct Fraction {
    Wide numerator;
    Wide denominator;
};

inline bool equal(
    const Fraction& fraction,
    Wide numerator,
    Wide denominator
) {
    return fraction.numerator * denominator ==
           numerator * fraction.denominator;
}

inline Wide coordinate_bound(
    Wide maximum,
    Wide offset,
    Wide step
) {
    return step == 0 ? maximum : (maximum - offset) / step;
}

inline Fraction multiply_add(
    const Fraction& first,
    Wide multiplier,
    const Fraction& second
) {
    return {
        first.numerator * multiplier + second.numerator,
        first.denominator * multiplier + second.denominator
    };
}

}  // namespace rational_approximation_detail

// Returns the closest reduced fractions below and above numerator/denominator
// whose positive numerator and denominator are both at most maximum.
template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
RationalApproximationResult<T> rational_approximation(
    T maximum,
    T numerator,
    T denominator
) {
    assert(maximum > 0);
    assert(numerator > 0);
    assert(denominator > 0);
    static_assert(sizeof(T) <= sizeof(uint64_t));

    using rational_approximation_detail::Fraction;
    using rational_approximation_detail::Wide;
    using rational_approximation_detail::coordinate_bound;
    using rational_approximation_detail::equal;
    using rational_approximation_detail::multiply_add;

    const Wide limit = static_cast<std::make_unsigned_t<T>>(maximum);
    const Wide target_numerator =
        static_cast<std::make_unsigned_t<T>>(numerator);
    const Wide target_denominator =
        static_cast<std::make_unsigned_t<T>>(denominator);
    Fraction lower{0, 1};
    Fraction upper{1, 0};

    while (true) {
        Wide lower_multiplier = limit;
        lower_multiplier = std::min(
            lower_multiplier,
            coordinate_bound(limit, lower.numerator, upper.numerator)
        );
        lower_multiplier = std::min(
            lower_multiplier,
            coordinate_bound(limit, lower.denominator, upper.denominator)
        );
        const Wide lower_slack =
            target_numerator * lower.denominator -
            lower.numerator * target_denominator;
        const Wide lower_step =
            upper.numerator * target_denominator -
            target_numerator * upper.denominator;
        assert(lower_step != 0);
        lower_multiplier = std::min(
            lower_multiplier, lower_slack / lower_step
        );
        lower = multiply_add(upper, lower_multiplier, lower);
        if (equal(lower, target_numerator, target_denominator)) {
            upper = lower;
            break;
        }

        Wide upper_multiplier = limit;
        upper_multiplier = std::min(
            upper_multiplier,
            coordinate_bound(limit, upper.numerator, lower.numerator)
        );
        upper_multiplier = std::min(
            upper_multiplier,
            coordinate_bound(limit, upper.denominator, lower.denominator)
        );
        const Wide upper_slack =
            upper.numerator * target_denominator -
            target_numerator * upper.denominator;
        const Wide upper_step =
            target_numerator * lower.denominator -
            lower.numerator * target_denominator;
        assert(upper_step != 0);
        upper_multiplier = std::min(
            upper_multiplier, upper_slack / upper_step
        );
        upper = multiply_add(lower, upper_multiplier, upper);
        if (equal(upper, target_numerator, target_denominator)) {
            lower = upper;
            break;
        }

        if (lower_multiplier == 0 && upper_multiplier == 0) break;
    }

    RationalApproximationResult<T> result;
    result.lower = {
        static_cast<T>(lower.numerator),
        static_cast<T>(lower.denominator)
    };
    result.upper = {
        static_cast<T>(upper.numerator),
        static_cast<T>(upper.denominator)
    };
    return result;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/repunit.hpp"



#line 9 "math/repunit.hpp"

namespace m1une {
namespace math {

template <class T>
constexpr std::pair<T, T> repunit_and_power(
    std::uint64_t length,
    T base = T(10)
) {
    T result = T(0);
    T result_power = T(1);
    T block = T(1);
    T block_power = base;

    while (length > 0) {
        if (length & 1) {
            result = result * block_power + block;
            result_power = result_power * block_power;
        }
        block = block * block_power + block;
        block_power = block_power * block_power;
        length >>= 1;
    }
    return std::make_pair(result, result_power);
}

// Returns 1 + base + ... + base^(length - 1).
// The arithmetic, including any modular reduction, is performed by T.
template <class T>
constexpr T repunit(std::uint64_t length, T base = T(10)) {
    return repunit_and_power<T>(length, base).first;
}

template <class T>
constexpr T repdigit(std::uint64_t length, T digit, T base = T(10)) {
    return digit * repunit<T>(length, base);
}

template <class T>
constexpr T concatenate_digits(
    T left,
    T right,
    std::uint64_t right_length,
    T base = T(10)
) {
    return left * repunit_and_power<T>(right_length, base).second + right;
}

namespace repunit_detail {

inline std::uint64_t multiply_mod(
    std::uint64_t left,
    std::uint64_t right,
    std::uint64_t mod
) {
    return static_cast<std::uint64_t>(
        static_cast<unsigned __int128>(left) * right % mod
    );
}

inline std::pair<std::uint64_t, std::uint64_t> repunit_and_power_mod(
    std::uint64_t length,
    std::uint64_t base,
    std::uint64_t mod
) {
    if (mod == 1) return std::make_pair(0, 0);

    std::uint64_t result = 0;
    std::uint64_t result_power = 1;
    std::uint64_t block = 1;
    std::uint64_t block_power = base % mod;
    while (length > 0) {
        if (length & 1) {
            result = (
                static_cast<unsigned __int128>(result) * block_power + block
            ) % mod;
            result_power = multiply_mod(result_power, block_power, mod);
        }
        block = (
            static_cast<unsigned __int128>(block) * block_power + block
        ) % mod;
        block_power = multiply_mod(block_power, block_power, mod);
        length >>= 1;
    }
    return std::make_pair(result, result_power);
}

}  // namespace repunit_detail

inline std::pair<std::uint64_t, std::uint64_t> repunit_and_power_mod(
    std::uint64_t length,
    std::uint64_t base,
    std::uint64_t mod
) {
    assert(mod >= 1);
    return repunit_detail::repunit_and_power_mod(length, base, mod);
}

inline std::uint64_t repunit_mod(
    std::uint64_t length,
    std::uint64_t base,
    std::uint64_t mod
) {
    return repunit_and_power_mod(length, base, mod).first;
}

inline std::uint64_t repdigit_mod(
    std::uint64_t length,
    std::uint64_t digit,
    std::uint64_t base,
    std::uint64_t mod
) {
    assert(mod >= 1);
    if (mod == 1) return 0;
    return repunit_detail::multiply_mod(
        digit % mod,
        repunit_mod(length, base, mod),
        mod
    );
}

inline std::uint64_t concatenate_digits_mod(
    std::uint64_t left,
    std::uint64_t right,
    std::uint64_t right_length,
    std::uint64_t base,
    std::uint64_t mod
) {
    assert(mod >= 1);
    if (mod == 1) return 0;
    const std::uint64_t power =
        repunit_and_power_mod(right_length, base, mod).second;
    return (
        static_cast<unsigned __int128>(left % mod) * power + right % mod
    ) % mod;
}

inline std::optional<std::uint64_t> minimum_repunit_length(
    std::uint64_t divisor,
    std::uint64_t base = 10
) {
    assert(divisor >= 1);
    assert(base >= 2);
    if (std::gcd(divisor, base) != 1) return std::nullopt;

    std::uint64_t remainder = 0;
    for (std::uint64_t length = 1; length <= divisor; length++) {
        remainder = (
            static_cast<unsigned __int128>(remainder) * base + 1
        ) % divisor;
        if (remainder == 0) return length;
    }
    return std::nullopt;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/set_power_series.hpp"



#line 11 "math/set_power_series.hpp"

#line 1 "math/subset_convolution.hpp"



#line 10 "math/subset_convolution.hpp"

namespace m1une {
namespace math {

template <typename T>
std::vector<T> subset_convolution(
    std::vector<T> first,
    std::vector<T> second
) {
    assert(first.size() == second.size());
    if (first.empty()) return {};
    assert((first.size() & (first.size() - 1)) == 0);

    const std::size_t size = first.size();
    std::size_t bit_count = 0;
    while ((std::size_t(1) << bit_count) < size) ++bit_count;
    const std::size_t rank_count = bit_count + 1;

    std::vector<T> first_ranked(size * rank_count);
    std::vector<T> second_ranked(size * rank_count);
    for (std::size_t mask = 0; mask < size; ++mask) {
        const std::size_t rank = std::popcount(mask);
        first_ranked[mask * rank_count + rank] = std::move(first[mask]);
        second_ranked[mask * rank_count + rank] = std::move(second[mask]);
    }

    for (std::size_t bit = 1; bit < size; bit <<= 1) {
        for (std::size_t mask = 0; mask < size; ++mask) {
            if ((mask & bit) == 0) continue;
            const std::size_t destination = mask * rank_count;
            const std::size_t source = (mask ^ bit) * rank_count;
            for (std::size_t rank = 0; rank < rank_count; ++rank) {
                first_ranked[destination + rank] +=
                    first_ranked[source + rank];
                second_ranked[destination + rank] +=
                    second_ranked[source + rank];
            }
        }
    }

    std::vector<T> product(rank_count);
    for (std::size_t mask = 0; mask < size; ++mask) {
        for (T& value : product) value = T{};
        const std::size_t offset = mask * rank_count;
        const std::size_t rank_limit = std::popcount(mask);
        for (std::size_t left = 0; left <= rank_limit; ++left) {
            const std::size_t right_limit =
                std::min(rank_limit, bit_count - left);
            for (std::size_t right = 0; right <= right_limit; ++right) {
                product[left + right] +=
                    first_ranked[offset + left] *
                    second_ranked[offset + right];
            }
        }
        for (std::size_t rank = 0; rank < rank_count; ++rank) {
            first_ranked[offset + rank] = std::move(product[rank]);
        }
    }

    for (std::size_t bit = 1; bit < size; bit <<= 1) {
        for (std::size_t mask = 0; mask < size; ++mask) {
            if ((mask & bit) == 0) continue;
            const std::size_t destination = mask * rank_count;
            const std::size_t source = (mask ^ bit) * rank_count;
            for (std::size_t rank = 0; rank < rank_count; ++rank) {
                first_ranked[destination + rank] -=
                    first_ranked[source + rank];
            }
        }
    }

    std::vector<T> result(size);
    for (std::size_t mask = 0; mask < size; ++mask) {
        result[mask] = std::move(
            first_ranked[mask * rank_count + std::popcount(mask)]
        );
    }
    return result;
}

}  // namespace math
}  // namespace m1une


#line 13 "math/set_power_series.hpp"

namespace m1une {
namespace math {

namespace set_power_series_detail {

inline bool is_power_of_two(std::size_t size) {
    return size != 0 && (size & (size - 1)) == 0;
}

template <class T>
std::vector<T> divide(
    const std::vector<T>& numerator,
    const std::vector<T>& denominator
) {
    assert(numerator.size() == denominator.size());
    assert(is_power_of_two(numerator.size()));
    assert(denominator[0] != T{});

    const std::size_t size = numerator.size();
    const int bit_count = std::countr_zero(size);
    const std::size_t rank_count = std::size_t(bit_count) + 1;
    std::vector<T> denominator_ranked(size * rank_count);
    std::vector<T> quotient_ranked(size * rank_count);

    for (std::size_t mask = 0; mask < size; mask++) {
        std::size_t rank = std::popcount(mask);
        denominator_ranked[mask * rank_count + rank] = denominator[mask];
    }
    for (std::size_t bit = 1; bit < size; bit <<= 1) {
        for (std::size_t mask = 0; mask < size; mask++) {
            if ((mask & bit) == 0) continue;
            std::size_t source_mask = mask ^ bit;
            std::size_t source = source_mask * rank_count;
            std::size_t destination = mask * rank_count;
            std::size_t rank_limit = std::popcount(source_mask);
            for (std::size_t rank = 0; rank <= rank_limit; rank++) {
                denominator_ranked[destination + rank] +=
                    denominator_ranked[source + rank];
            }
        }
    }

    const T inverse_constant = T(1) / denominator[0];
    std::vector<T> transformed_product(size);
    std::vector<T> quotient(size);
    for (int rank = 0; rank <= bit_count; rank++) {
        std::fill(
            transformed_product.begin(),
            transformed_product.end(),
            T{}
        );
        for (std::size_t mask = 0; mask < size; mask++) {
            std::size_t offset = mask * rank_count;
            for (int left_rank = 0; left_rank <= rank; left_rank++) {
                transformed_product[mask] +=
                    denominator_ranked[offset + left_rank] *
                    quotient_ranked[offset + rank - left_rank];
            }
        }

        for (std::size_t bit = 1; bit < size; bit <<= 1) {
            for (std::size_t mask = 0; mask < size; mask++) {
                if (mask & bit) {
                    transformed_product[mask] -=
                        transformed_product[mask ^ bit];
                }
            }
        }

        for (std::size_t mask = 0; mask < size; mask++) {
            if (int(std::popcount(mask)) != rank) continue;
            quotient[mask] =
                (numerator[mask] - transformed_product[mask]) *
                inverse_constant;
            quotient_ranked[mask * rank_count + rank] = quotient[mask];
        }

        for (std::size_t bit = 1; bit < size; bit <<= 1) {
            for (std::size_t mask = 0; mask < size; mask++) {
                if (mask & bit) {
                    quotient_ranked[mask * rank_count + rank] +=
                        quotient_ranked[(mask ^ bit) * rank_count + rank];
                }
            }
        }
    }
    return quotient;
}

template <class T>
std::vector<T> normalized_power(std::vector<T> series, T exponent) {
    assert(is_power_of_two(series.size()));
    assert(series[0] == T(1));
    std::vector<T> logarithm(series.size());
    logarithm[0] = T{};
    for (std::size_t half = 1; half < series.size(); half <<= 1) {
        std::vector<T> low(series.begin(), series.begin() + half);
        std::vector<T> high(
            series.begin() + half,
            series.begin() + 2 * half
        );
        std::vector<T> next = divide(high, low);
        std::move(next.begin(), next.end(), logarithm.begin() + half);
    }
    for (T& value : logarithm) value *= exponent;

    std::vector<T> result(1, T(1));
    result.reserve(series.size());
    for (std::size_t half = 1; half < series.size(); half <<= 1) {
        std::vector<T> high(
            logarithm.begin() + half,
            logarithm.begin() + 2 * half
        );
        std::vector<T> next = subset_convolution(std::move(high), result);
        result.insert(
            result.end(),
            std::make_move_iterator(next.begin()),
            std::make_move_iterator(next.end())
        );
    }
    return result;
}

}  // namespace set_power_series_detail

// Returns numerator / denominator under subset convolution.
template <class T>
std::vector<T> set_power_series_divide(
    const std::vector<T>& numerator,
    const std::vector<T>& denominator
) {
    return set_power_series_detail::divide(numerator, denominator);
}

template <class T>
std::vector<T> set_power_series_inverse(const std::vector<T>& series) {
    assert(set_power_series_detail::is_power_of_two(series.size()));
    std::vector<T> identity(series.size());
    identity[0] = T(1);
    return set_power_series_divide(identity, series);
}

template <class T>
std::vector<T> set_power_series_exp(const std::vector<T>& series) {
    assert(set_power_series_detail::is_power_of_two(series.size()));
    assert(series[0] == T{});
    std::vector<T> result(1, T(1));
    result.reserve(series.size());
    for (std::size_t half = 1; half < series.size(); half <<= 1) {
        std::vector<T> high(
            series.begin() + half,
            series.begin() + 2 * half
        );
        std::vector<T> next = subset_convolution(std::move(high), result);
        result.insert(
            result.end(),
            std::make_move_iterator(next.begin()),
            std::make_move_iterator(next.end())
        );
    }
    return result;
}

template <class T>
std::vector<T> set_power_series_log(const std::vector<T>& series) {
    assert(set_power_series_detail::is_power_of_two(series.size()));
    assert(series[0] == T(1));
    std::vector<T> result(series.size());
    for (std::size_t half = 1; half < series.size(); half <<= 1) {
        std::vector<T> low(series.begin(), series.begin() + half);
        std::vector<T> high(
            series.begin() + half,
            series.begin() + 2 * half
        );
        std::vector<T> next = set_power_series_divide(high, low);
        std::move(next.begin(), next.end(), result.begin() + half);
    }
    return result;
}

template <class T>
std::vector<T> set_power_series_pow(
    const std::vector<T>& series,
    long long exponent
) {
    return set_power_series_detail::normalized_power(
        series,
        T(exponent)
    );
}

template <class T>
std::vector<T> set_power_series_sqrt(const std::vector<T>& series) {
    return set_power_series_detail::normalized_power(
        series,
        T(1) / T(2)
    );
}

}  // namespace math
}  // namespace m1une


#line 1 "math/squarefree_count.hpp"



#line 9 "math/squarefree_count.hpp"

#line 11 "math/squarefree_count.hpp"

namespace m1une {
namespace math {

namespace squarefree_count_detail {

inline std::vector<int> mobius_prefix(int limit) {
    std::vector<std::int8_t> mobius(limit + 1, 0);
    if (limit >= 1) mobius[1] = 1;
    {
        std::vector<int> primes;
        std::vector<bool> composite(limit + 1, false);
        for (int value = 2; value <= limit; value++) {
            if (!composite[value]) {
                primes.push_back(value);
                mobius[value] = -1;
            }
            for (int prime : primes) {
                if (prime > limit / value) break;
                const int product = prime * value;
                composite[product] = true;
                if (value % prime == 0) {
                    mobius[product] = 0;
                    break;
                }
                mobius[product] = static_cast<std::int8_t>(-mobius[value]);
            }
        }
    }

    std::vector<int> prefix(limit + 1, 0);
    for (int value = 1; value <= limit; value++) {
        prefix[value] = prefix[value - 1] + mobius[value];
    }
    return prefix;
}

}  // namespace squarefree_count_detail

// Returns the number of square-free positive integers not greater than n.
inline uint64_t count_squarefree(uint64_t n) {
    if (n == 0) return 0;

    const uint64_t split = std::max<uint64_t>(1, floor_kth_root(n, 5U));
    const uint64_t sieve_limit_u64 = isqrt(n / split);
    assert(
        sieve_limit_u64 <=
        static_cast<uint64_t>(std::numeric_limits<int>::max())
    );
    const int sieve_limit = static_cast<int>(sieve_limit_u64);
    const std::vector<int> mertens =
        squarefree_count_detail::mobius_prefix(sieve_limit);

    __int128_t direct_sum = 0;
    for (int divisor = 1; divisor <= sieve_limit; divisor++) {
        direct_sum += static_cast<__int128_t>(
            n / static_cast<uint64_t>(divisor) /
            static_cast<uint64_t>(divisor)
        ) * (mertens[divisor] - mertens[divisor - 1]);
    }

    std::vector<std::int64_t> large_mertens;
    large_mertens.reserve(split - 1);
    std::int64_t large_mertens_sum = 0;
    for (uint64_t index = split; index-- > 1;) {
        const uint64_t argument = isqrt(n / index);
        const uint64_t square_root = isqrt(argument);
        std::int64_t value = 1;

        const uint64_t small_quotient_limit =
            argument / (square_root + 1);
        for (uint64_t quotient = 1;
             quotient <= small_quotient_limit;
             quotient++) {
            const uint64_t multiplicity =
                argument / quotient - argument / (quotient + 1);
            value -= static_cast<std::int64_t>(multiplicity) *
                     mertens[static_cast<int>(quotient)];
        }
        for (uint64_t divisor = 2; divisor <= square_root; divisor++) {
            const uint64_t quotient = argument / divisor;
            if (quotient <= sieve_limit_u64) {
                value -= mertens[static_cast<int>(quotient)];
            } else {
                const uint64_t previous_argument =
                    index * divisor * divisor;
                assert(previous_argument < split);
                const uint64_t position = split - previous_argument - 1;
                assert(position < large_mertens.size());
                value -= large_mertens[position];
            }
        }
        large_mertens.push_back(value);
        large_mertens_sum += value;
    }

    const std::int64_t grouped_sum =
        large_mertens_sum -
        static_cast<std::int64_t>(split - 1) * mertens[sieve_limit];
    const __int128_t answer = direct_sum + grouped_sum;
    assert(answer >= 0);
    assert(answer <= std::numeric_limits<uint64_t>::max());
    return static_cast<uint64_t>(answer);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/stern_brocot_tree.hpp"



#line 10 "math/stern_brocot_tree.hpp"

#line 12 "math/stern_brocot_tree.hpp"

namespace m1une {
namespace math {

enum class SternBrocotDirection {
    Left,
    Right,
};

struct SternBrocotRun {
    SternBrocotDirection direction;
    uint64_t count;

    friend bool operator==(const SternBrocotRun&, const SternBrocotRun&) = default;
};

struct SternBrocotPath {
    std::vector<SternBrocotRun> runs;

    bool empty() const {
        return runs.empty();
    }

    uint64_t depth() const {
        uint64_t result = 0;
        for (const SternBrocotRun& run : runs) {
            assert(run.count <= std::numeric_limits<uint64_t>::max() - result);
            result += run.count;
        }
        return result;
    }

    void push(SternBrocotDirection direction, uint64_t count = 1) {
        if (count == 0) return;
        if (!runs.empty() && runs.back().direction == direction) {
            assert(count <= std::numeric_limits<uint64_t>::max() - runs.back().count);
            runs.back().count += count;
        } else {
            runs.push_back(SternBrocotRun{direction, count});
        }
    }

    bool move_up(uint64_t count = 1) {
        if (depth() < count) return false;
        while (count > 0) {
            SternBrocotRun& run = runs.back();
            uint64_t removed = run.count < count ? run.count : count;
            run.count -= removed;
            count -= removed;
            if (run.count == 0) runs.pop_back();
        }
        return true;
    }

    SternBrocotPath ancestor(uint64_t count) const {
        SternBrocotPath result = *this;
        [[maybe_unused]] bool valid = result.move_up(count);
        assert(valid);
        return result;
    }

    friend bool operator==(const SternBrocotPath&, const SternBrocotPath&) = default;
};

template <std::signed_integral T = long long>
struct SternBrocotBounds {
    std::pair<T, T> left;
    std::pair<T, T> right;
};

template <std::signed_integral T>
SternBrocotPath stern_brocot_path(T numerator, T denominator) {
    assert(0 < numerator);
    assert(0 < denominator);
    SternBrocotPath result;
    while (numerator != denominator) {
        if (numerator < denominator) {
            T count = (denominator - 1) / numerator;
            result.push(SternBrocotDirection::Left, uint64_t(count));
            denominator -= count * numerator;
        } else {
            T count = (numerator - 1) / denominator;
            result.push(SternBrocotDirection::Right, uint64_t(count));
            numerator -= count * denominator;
        }
    }
    assert(numerator == 1);
    return result;
}

template <std::signed_integral T = long long>
Rational<T> stern_brocot_decode(const SternBrocotPath& path) {
    using Wide = __int128_t;
    Wide left_numerator = 0;
    Wide left_denominator = 1;
    Wide right_numerator = 1;
    Wide right_denominator = 0;
    Wide numerator = 1;
    Wide denominator = 1;
    [[maybe_unused]] const Wide maximum = std::numeric_limits<T>::max();
    for (const SternBrocotRun& run : path.runs) {
        assert(run.count > 0);
        assert(Wide(run.count) <= maximum);
        Wide count = run.count;
        if (run.direction == SternBrocotDirection::Left) {
            right_numerator = numerator + (count - 1) * left_numerator;
            right_denominator = denominator + (count - 1) * left_denominator;
            numerator += count * left_numerator;
            denominator += count * left_denominator;
        } else {
            left_numerator = numerator + (count - 1) * right_numerator;
            left_denominator = denominator + (count - 1) * right_denominator;
            numerator += count * right_numerator;
            denominator += count * right_denominator;
        }
        assert(numerator <= maximum);
        assert(denominator <= maximum);
        assert(left_numerator <= maximum);
        assert(left_denominator <= maximum);
        assert(right_numerator <= maximum);
        assert(right_denominator <= maximum);
    }
    return Rational<T>(T(numerator), T(denominator));
}

template <std::signed_integral T>
uint64_t stern_brocot_depth(T numerator, T denominator) {
    return stern_brocot_path(numerator, denominator).depth();
}

inline SternBrocotPath stern_brocot_lca_path(
    const SternBrocotPath& first,
    const SternBrocotPath& second
) {
    SternBrocotPath result;
    int limit = int(first.runs.size() < second.runs.size() ? first.runs.size() : second.runs.size());
    for (int i = 0; i < limit; i++) {
        if (first.runs[i].direction != second.runs[i].direction) break;
        uint64_t common =
            first.runs[i].count < second.runs[i].count
                ? first.runs[i].count
                : second.runs[i].count;
        result.push(first.runs[i].direction, common);
        if (first.runs[i].count != second.runs[i].count) break;
    }
    return result;
}

template <std::signed_integral T>
Rational<T> stern_brocot_lca(
    T first_numerator,
    T first_denominator,
    T second_numerator,
    T second_denominator
) {
    SternBrocotPath path = stern_brocot_lca_path(
        stern_brocot_path(first_numerator, first_denominator),
        stern_brocot_path(second_numerator, second_denominator)
    );
    return stern_brocot_decode<T>(path);
}

template <std::signed_integral T>
Rational<T> stern_brocot_ancestor(T numerator, T denominator, uint64_t up) {
    SternBrocotPath path = stern_brocot_path(numerator, denominator);
    [[maybe_unused]] bool valid = path.move_up(up);
    assert(valid);
    return stern_brocot_decode<T>(path);
}

template <std::signed_integral T>
Rational<T> stern_brocot_parent(T numerator, T denominator) {
    return stern_brocot_ancestor(numerator, denominator, 1);
}

template <std::signed_integral T>
Rational<T> stern_brocot_move(
    T numerator,
    T denominator,
    SternBrocotDirection direction,
    uint64_t count = 1
) {
    SternBrocotPath path = stern_brocot_path(numerator, denominator);
    path.push(direction, count);
    return stern_brocot_decode<T>(path);
}

template <std::signed_integral T = long long>
SternBrocotBounds<T> stern_brocot_bounds(const SternBrocotPath& path) {
    using Wide = __int128_t;
    Wide left_numerator = 0;
    Wide left_denominator = 1;
    Wide right_numerator = 1;
    Wide right_denominator = 0;
    Wide numerator = 1;
    Wide denominator = 1;
    [[maybe_unused]] const Wide maximum = std::numeric_limits<T>::max();

    for (const SternBrocotRun& run : path.runs) {
        assert(run.count > 0);
        assert(Wide(run.count) <= maximum);
        Wide count = run.count;
        if (run.direction == SternBrocotDirection::Left) {
            right_numerator = numerator + (count - 1) * left_numerator;
            right_denominator = denominator + (count - 1) * left_denominator;
            numerator += count * left_numerator;
            denominator += count * left_denominator;
        } else {
            left_numerator = numerator + (count - 1) * right_numerator;
            left_denominator = denominator + (count - 1) * right_denominator;
            numerator += count * right_numerator;
            denominator += count * right_denominator;
        }
        assert(numerator <= maximum);
        assert(denominator <= maximum);
        assert(left_numerator <= maximum);
        assert(left_denominator <= maximum);
        assert(right_numerator <= maximum);
        assert(right_denominator <= maximum);
    }
    SternBrocotBounds<T> result;
    result.left = {T(left_numerator), T(left_denominator)};
    result.right = {T(right_numerator), T(right_denominator)};
    return result;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/tetration.hpp"



#line 9 "math/tetration.hpp"

#line 11 "math/tetration.hpp"

namespace m1une {
namespace math {

namespace tetration_detail {

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
uint64_t to_uint64(T value) {
    if constexpr (std::signed_integral<T>) {
        assert(value >= 0);
    }
    return static_cast<uint64_t>(value);
}

inline uint64_t multiply_mod(uint64_t first, uint64_t second, uint64_t mod) {
    return static_cast<uint64_t>(
        static_cast<__uint128_t>(first) * second % mod
    );
}

inline uint64_t pow_mod(uint64_t base, __uint128_t exponent, uint64_t mod) {
    assert(mod >= 1);
    if (mod == 1) return 0;
    base %= mod;
    uint64_t result = 1 % mod;
    while (exponent > 0) {
        if ((exponent & 1) != 0) result = multiply_mod(result, base, mod);
        base = multiply_mod(base, base, mod);
        exponent >>= 1;
    }
    return result;
}

inline uint64_t pow_bounded(uint64_t base, uint64_t exponent, uint64_t limit) {
    if (limit == 0) return 0;
    __uint128_t result = 1;
    for (uint64_t i = 0; i < exponent; i++) {
        result *= base;
        if (result >= limit) return limit;
    }
    return static_cast<uint64_t>(result);
}

inline uint64_t exponent_threshold(uint64_t base, uint64_t limit) {
    assert(base >= 2);
    if (limit <= 1) return 0;

    uint64_t exponent = 0;
    uint64_t value = 1;
    while (value < limit) {
        exponent++;
        if (value > limit / base) return exponent;
        value *= base;
    }
    return exponent;
}

inline uint64_t tetration_bounded_unsigned(uint64_t base, uint64_t height, uint64_t limit) {
    if (limit == 0) return 0;
    if (height == 0) return limit < 1 ? limit : 1;
    if (height == 1) return base < limit ? base : limit;

    if (base == 0) {
        const uint64_t value = (height & 1) == 0 ? 1 : 0;
        return value < limit ? value : limit;
    }
    if (base == 1) return limit < 1 ? limit : 1;

    const uint64_t threshold = exponent_threshold(base, limit);
    const uint64_t exponent = tetration_bounded_unsigned(base, height - 1, threshold);
    if (exponent >= threshold) return limit;
    return pow_bounded(base, exponent, limit);
}

inline uint64_t tetration_mod_unsigned(uint64_t base, uint64_t height, uint64_t mod) {
    assert(mod >= 1);
    if (mod == 1) return 0;
    if (height == 0) return 1 % mod;
    if (height == 1) return base % mod;
    if (base == 0) return (height & 1) == 0 ? 1 % mod : 0;
    if (base == 1) return 1 % mod;

    const uint64_t phi = euler_phi(mod);
    uint64_t reduced_exponent = tetration_mod_unsigned(base, height - 1, phi);
    __uint128_t exponent = reduced_exponent;
    if (tetration_bounded_unsigned(base, height - 1, phi) >= phi) {
        exponent += phi;
    }
    return pow_mod(base, exponent, mod);
}

inline uint64_t power_tower_bounded_unsigned(
    const std::vector<uint64_t>& bases,
    int index,
    uint64_t limit
) {
    if (limit == 0) return 0;
    if (index == int(bases.size())) return limit < 1 ? limit : 1;

    const uint64_t base = bases[index];
    if (index + 1 == int(bases.size())) return base < limit ? base : limit;

    if (base == 0) {
        const uint64_t exponent = power_tower_bounded_unsigned(bases, index + 1, 1);
        const uint64_t value = exponent == 0 ? 1 : 0;
        return value < limit ? value : limit;
    }
    if (base == 1) return limit < 1 ? limit : 1;

    const uint64_t threshold = exponent_threshold(base, limit);
    const uint64_t exponent = power_tower_bounded_unsigned(bases, index + 1, threshold);
    if (exponent >= threshold) return limit;
    return pow_bounded(base, exponent, limit);
}

inline uint64_t power_tower_mod_unsigned(
    const std::vector<uint64_t>& bases,
    int index,
    uint64_t mod
) {
    assert(mod >= 1);
    if (mod == 1) return 0;
    if (index == int(bases.size())) return 1 % mod;
    if (index + 1 == int(bases.size())) return bases[index] % mod;

    const uint64_t phi = euler_phi(mod);
    uint64_t reduced_exponent = power_tower_mod_unsigned(bases, index + 1, phi);
    __uint128_t exponent = reduced_exponent;
    if (power_tower_bounded_unsigned(bases, index + 1, phi) >= phi) {
        exponent += phi;
    }
    return pow_mod(bases[index], exponent, mod);
}

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
std::vector<uint64_t> normalize_bases(const std::vector<T>& bases) {
    std::vector<uint64_t> result;
    result.reserve(bases.size());
    for (T base : bases) result.push_back(to_uint64(base));
    return result;
}

}  // namespace tetration_detail

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
uint64_t tetration_mod(T base, uint64_t height, uint64_t mod) {
    assert(mod >= 1);
    return tetration_detail::tetration_mod_unsigned(
        tetration_detail::to_uint64(base),
        height,
        mod
    );
}

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
uint64_t tetration_bounded(T base, uint64_t height, uint64_t limit) {
    return tetration_detail::tetration_bounded_unsigned(
        tetration_detail::to_uint64(base),
        height,
        limit
    );
}

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
uint64_t power_tower_mod(const std::vector<T>& bases, uint64_t mod) {
    assert(mod >= 1);
    std::vector<uint64_t> normalized = tetration_detail::normalize_bases(bases);
    return tetration_detail::power_tower_mod_unsigned(normalized, 0, mod);
}

template <std::integral T>
requires(!std::same_as<std::remove_cv_t<T>, bool>)
uint64_t power_tower_bounded(const std::vector<T>& bases, uint64_t limit) {
    std::vector<uint64_t> normalized = tetration_detail::normalize_bases(bases);
    return tetration_detail::power_tower_bounded_unsigned(normalized, 0, limit);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/totient_sum.hpp"



#line 8 "math/totient_sum.hpp"

namespace m1une {
namespace math {

struct TotientSum {
   private:
    int _precalculation_limit;
    std::vector<__uint128_t> _prefix_sum;
    std::unordered_map<uint64_t, __uint128_t> _memo;

    __uint128_t solve(uint64_t n) {
        if (n <= static_cast<uint64_t>(_precalculation_limit)) {
            return _prefix_sum[static_cast<int>(n)];
        }
        if (auto it = _memo.find(n); it != _memo.end()) {
            return it->second;
        }

        const __uint128_t wide_n = n;
        __uint128_t result = wide_n * (wide_n + 1) / 2;
        for (uint64_t left = 2; left <= n;) {
            const uint64_t quotient = n / left;
            const uint64_t right = n / quotient;
            result -= static_cast<__uint128_t>(right - left + 1) * solve(quotient);
            if (right == n) break;
            left = right + 1;
        }

        _memo.emplace(n, result);
        return result;
    }

   public:
    explicit TotientSum(int precalculation_limit = 1000000) : _precalculation_limit(precalculation_limit) {
        assert(precalculation_limit >= 0);

        std::vector<uint64_t> phi(precalculation_limit + 1);
        std::vector<int> primes;
        std::vector<bool> is_composite(precalculation_limit + 1);
        if (precalculation_limit >= 1) {
            phi[1] = 1;
        }
        for (int value = 2; value <= precalculation_limit; value++) {
            if (!is_composite[value]) {
                primes.push_back(value);
                phi[value] = static_cast<uint64_t>(value - 1);
            }
            for (int prime : primes) {
                if (value > precalculation_limit / prime) break;
                const int next = value * prime;
                is_composite[next] = true;
                if (value % prime == 0) {
                    phi[next] = phi[value] * static_cast<uint64_t>(prime);
                    break;
                }
                phi[next] = phi[value] * static_cast<uint64_t>(prime - 1);
            }
        }

        _prefix_sum.assign(precalculation_limit + 1, 0);
        for (int value = 1; value <= precalculation_limit; value++) {
            _prefix_sum[value] = _prefix_sum[value - 1] + phi[value];
        }
    }

    int precalculation_limit() const {
        return _precalculation_limit;
    }

    // Returns sum_{i=1}^n phi(i).
    __uint128_t prefix_sum(uint64_t n) {
        return solve(n);
    }

    __uint128_t operator()(uint64_t n) {
        return prefix_sum(n);
    }
};

inline __uint128_t totient_sum(uint64_t n, int precalculation_limit = 1000000) {
    TotientSum solver(precalculation_limit);
    return solver.prefix_sum(n);
}

}  // namespace math
}  // namespace m1une


#line 1 "math/two_square_sum.hpp"



#line 9 "math/two_square_sum.hpp"

#line 12 "math/two_square_sum.hpp"

namespace m1une {
namespace math {

namespace two_square_sum_detail {

struct GaussianInteger {
    __int128_t real;
    __int128_t imaginary;
};

inline GaussianInteger multiply(GaussianInteger first, GaussianInteger second) {
    return GaussianInteger{first.real * second.real - first.imaginary * second.imaginary,
                           first.real * second.imaginary + first.imaginary * second.real};
}

inline GaussianInteger power(GaussianInteger base, int exponent) {
    GaussianInteger result{1, 0};
    while (exponent > 0) {
        if ((exponent & 1) != 0) result = multiply(result, base);
        exponent >>= 1;
        if (exponent != 0) base = multiply(base, base);
    }
    return result;
}

inline uint64_t absolute_value(__int128_t value) {
    return static_cast<uint64_t>(value < 0 ? -value : value);
}

inline uint64_t pow_uint64(uint64_t base, int exponent) {
    uint64_t result = 1;
    while (exponent > 0) {
        if ((exponent & 1) != 0) result *= base;
        exponent >>= 1;
        if (exponent != 0) base *= base;
    }
    return result;
}

inline GaussianInteger prime_one_mod_four_representation(uint64_t prime) {
    assert(prime % 4 == 1);
    uint64_t non_residue = 2;
    while (internal::power_mod(non_residue, (prime - 1) / 2, prime) != prime - 1) {
        non_residue++;
    }

    uint64_t root = internal::power_mod(non_residue, (prime - 1) / 4, prime);
    uint64_t previous = prime;
    uint64_t current = root;
    while (static_cast<__uint128_t>(current) * current > prime) {
        uint64_t next = previous % current;
        previous = current;
        current = next;
    }

    const uint64_t real = current;
    const uint64_t remaining = prime - real * real;
    const uint64_t imaginary = isqrt(remaining);
    assert(imaginary * imaginary == remaining);
    return GaussianInteger{static_cast<__int128_t>(real), static_cast<__int128_t>(imaginary)};
}

inline std::vector<GaussianInteger> prime_power_choices(GaussianInteger factor, int exponent) {
    GaussianInteger conjugate{factor.real, -factor.imaginary};

    std::vector<GaussianInteger> positive_powers(exponent + 1);
    std::vector<GaussianInteger> negative_powers(exponent + 1);
    positive_powers[0] = GaussianInteger{1, 0};
    negative_powers[0] = GaussianInteger{1, 0};
    for (int i = 0; i < exponent; i++) {
        positive_powers[i + 1] = multiply(positive_powers[i], factor);
        negative_powers[i + 1] = multiply(negative_powers[i], conjugate);
    }

    std::vector<GaussianInteger> result;
    result.reserve(exponent + 1);
    for (int take_positive = 0; take_positive <= exponent; take_positive++) {
        result.push_back(multiply(positive_powers[take_positive], negative_powers[exponent - take_positive]));
    }
    return result;
}

inline void add_nonnegative_pairs(std::vector<std::pair<uint64_t, uint64_t>>& result, GaussianInteger value,
                                  uint64_t scale) {
    const uint64_t first = absolute_value(value.real) * scale;
    const uint64_t second = absolute_value(value.imaginary) * scale;
    result.emplace_back(first, second);
    result.emplace_back(second, first);
}

}  // namespace two_square_sum_detail

inline std::vector<std::pair<uint64_t, uint64_t>> two_square_sum(uint64_t value) {
    using two_square_sum_detail::GaussianInteger;

    if (value == 0) return std::vector<std::pair<uint64_t, uint64_t>>{std::pair<uint64_t, uint64_t>(0, 0)};

    uint64_t real_scale = 1;
    std::vector<std::vector<GaussianInteger>> choices_by_prime;
    for (const auto& factor : prime_factorize(value)) {
        const uint64_t prime = factor.first;
        const int exponent = factor.second;

        if (prime % 4 == 3) {
            if ((exponent & 1) != 0) return {};
            real_scale *= two_square_sum_detail::pow_uint64(prime, exponent / 2);
            continue;
        }

        GaussianInteger gaussian_factor;
        if (prime == 2) {
            gaussian_factor = GaussianInteger{1, 1};
        } else {
            gaussian_factor = two_square_sum_detail::prime_one_mod_four_representation(prime);
        }
        choices_by_prime.push_back(two_square_sum_detail::prime_power_choices(gaussian_factor, exponent));
    }

    std::vector<GaussianInteger> values;
    values.push_back(GaussianInteger{1, 0});
    for (const std::vector<GaussianInteger>& choices : choices_by_prime) {
        std::vector<GaussianInteger> next;
        next.reserve(values.size() * choices.size());
        for (GaussianInteger value_so_far : values) {
            for (GaussianInteger choice : choices) {
                next.push_back(two_square_sum_detail::multiply(value_so_far, choice));
            }
        }
        values.swap(next);
    }

    std::vector<std::pair<uint64_t, uint64_t>> result;
    result.reserve(values.size() * 2);
    for (GaussianInteger gaussian : values) {
        two_square_sum_detail::add_nonnegative_pairs(result, gaussian, real_scale);
    }

    std::sort(result.begin(), result.end());
    result.erase(std::unique(result.begin(), result.end()), result.end());
    return result;
}

inline std::vector<std::pair<uint64_t, uint64_t>> represent_as_two_square_sum(uint64_t value) {
    return two_square_sum(value);
}

inline bool is_two_square_sum(uint64_t value) {
    if (value == 0) return true;
    for (const auto& factor : prime_factorize(value)) {
        if (factor.first % 4 == 3 && (factor.second & 1) != 0) return false;
    }
    return true;
}

}  // namespace math
}  // namespace m1une


#line 1 "math/xor_basis.hpp"



#line 7 "math/xor_basis.hpp"
#include <initializer_list>
#line 11 "math/xor_basis.hpp"

namespace m1une {
namespace math {

template <std::unsigned_integral UInt = unsigned long long>
class XorBasis {
    static_assert(!std::same_as<UInt, bool>);

public:
    static constexpr int bit_width = std::numeric_limits<UInt>::digits;

    XorBasis() = default;

    template <std::input_iterator Iterator, std::sentinel_for<Iterator> Sentinel>
        requires std::convertible_to<std::iter_reference_t<Iterator>, UInt>
    XorBasis(Iterator first, Sentinel last) {
        for (; first != last; ++first) insert(UInt(*first));
    }

    XorBasis(std::initializer_list<UInt> values)
        : XorBasis(values.begin(), values.end()) {}

    bool insert(UInt value) {
        for (int bit = bit_width - 1; bit >= 0; bit--) {
            if (((value >> bit) & UInt(1)) == 0) continue;
            if (basis_[bit] != 0) {
                value ^= basis_[bit];
                continue;
            }

            for (int lower = bit - 1; lower >= 0; lower--) {
                if (((value >> lower) & UInt(1)) != 0) value ^= basis_[lower];
            }
            basis_[bit] = value;
            rank_++;
            for (int higher = bit + 1; higher < bit_width; higher++) {
                if (((basis_[higher] >> bit) & UInt(1)) != 0) {
                    basis_[higher] ^= value;
                }
            }
            return true;
        }
        return false;
    }

    bool contains(UInt value) const {
        for (int bit = bit_width - 1; bit >= 0; bit--) {
            if (((value >> bit) & UInt(1)) != 0) value ^= basis_[bit];
        }
        return value == 0;
    }

    int rank() const {
        return rank_;
    }

    bool empty() const {
        return rank_ == 0;
    }

    void clear() {
        basis_.fill(UInt(0));
        rank_ = 0;
    }

    int merge(const XorBasis& other) {
        const int old_rank = rank_;
        for (UInt value : other.basis_) {
            if (value != 0) insert(value);
        }
        return rank_ - old_rank;
    }

    UInt min_xor(UInt value = 0) const {
        for (int bit = bit_width - 1; bit >= 0; bit--) {
            if ((value ^ basis_[bit]) < value) value ^= basis_[bit];
        }
        return value;
    }

    UInt max_xor(UInt value = 0) const {
        for (int bit = bit_width - 1; bit >= 0; bit--) {
            if (value < (value ^ basis_[bit])) value ^= basis_[bit];
        }
        return value;
    }

    UInt kth_smallest(UInt index) const {
        if (rank_ < bit_width) assert(index < (UInt(1) << rank_));
        UInt result = 0;
        int coefficient = 0;
        for (int bit = 0; bit < bit_width; bit++) {
            if (basis_[bit] == 0) continue;
            if (((index >> coefficient) & UInt(1)) != 0) result ^= basis_[bit];
            coefficient++;
        }
        return result;
    }

    std::vector<UInt> vectors() const {
        std::vector<UInt> result;
        result.reserve(rank_);
        for (UInt value : basis_) {
            if (value != 0) result.push_back(value);
        }
        return result;
    }

private:
    std::array<UInt, bit_width> basis_{};
    int rank_ = 0;
};

}  // namespace math
}  // namespace m1une


#line 44 "math/all.hpp"


#line 12 "verify/math/math_algorithms.test.cpp"

long long floor_div(long long numerator, long long denominator) {
    long long quotient = numerator / denominator;
    if (numerator % denominator < 0) quotient--;
    return quotient;
}

void test_number_theory() {
    using m1une::math::crt;
    using m1une::math::floor_sum;
    using m1une::math::inv_gcd;
    using m1une::math::inv_mod;
    using m1une::math::pow_mod;

    assert(pow_mod(-2, 5, 13) == 7);
    assert(pow_mod(123, 0, 1) == 0);
    assert(inv_mod(3, 11) == 4);

    const auto inverse = inv_gcd(6, 15);
    assert(inverse.first == 3);
    assert((6 * inverse.second - inverse.first) % 15 == 0);

    const auto solution = crt(
        std::vector<long long>{2, 3, 2},
        std::vector<long long>{3, 5, 7}
    );
    assert(solution.first == 23);
    assert(solution.second == 105);
    const auto inconsistent = crt(
        std::vector<long long>{0, 1},
        std::vector<long long>{2, 4}
    );
    assert(inconsistent.second == 0);

    for (long long first_mod = 1; first_mod <= 12; first_mod++) {
        for (long long second_mod = 1; second_mod <= 12; second_mod++) {
            const long long combined_mod = std::lcm(first_mod, second_mod);
            for (long long first_remainder = -5; first_remainder <= 5;
                 first_remainder++) {
                for (long long second_remainder = -5; second_remainder <= 5;
                     second_remainder++) {
                    long long expected = -1;
                    for (long long value = 0; value < combined_mod; value++) {
                        if (
                            (value - first_remainder) % first_mod == 0 &&
                            (value - second_remainder) % second_mod == 0
                        ) {
                            expected = value;
                            break;
                        }
                    }
                    const auto actual = crt(
                        std::vector<long long>{first_remainder, second_remainder},
                        std::vector<long long>{first_mod, second_mod}
                    );
                    if (expected == -1) {
                        assert(actual.second == 0);
                    } else {
                        assert(actual.first == expected);
                        assert(actual.second == combined_mod);
                    }
                }
            }
        }
    }

    for (long long n = 0; n <= 15; n++) {
        for (long long mod = 1; mod <= 15; mod++) {
            for (long long a = -15; a <= 15; a++) {
                for (long long b = -15; b <= 15; b++) {
                    long long expected = 0;
                    for (long long i = 0; i < n; i++) {
                        expected += floor_div(a * i + b, mod);
                    }
                    assert(floor_sum(n, mod, a, b) == expected);
                }
            }
        }
    }
}

void test_prime_sieve() {
    m1une::math::PrimeSieve sieve(100);
    assert(sieve.primes().size() == 25);
    assert(sieve.is_prime(97));
    assert(!sieve.is_prime(1));
    assert(sieve.min_prime_factor(91) == 7);

    std::vector<std::pair<int, int>> factors_72;
    factors_72.emplace_back(2, 3);
    factors_72.emplace_back(3, 2);
    assert(sieve.factorize(72) == factors_72);

    std::vector<std::pair<int, int>> factors_90;
    factors_90.emplace_back(2, 1);
    factors_90.emplace_back(3, 2);
    factors_90.emplace_back(5, 1);
    assert(sieve.factorize(90) == factors_90);

    const std::vector<int> expected_divisors = {1, 2, 3, 4, 6, 12};
    assert(sieve.divisors(12) == expected_divisors);
    assert(sieve.totient(36) == 12);
    assert(sieve.mobius(30) == -1);
    assert(sieve.mobius(12) == 0);
    assert(sieve.totient_table()[36] == 12);
    assert(sieve.mobius_table()[30] == -1);
}

void test_large_factorization() {
    using m1une::math::divisors;
    using m1une::math::euler_phi;
    using m1une::math::is_prime;
    using m1une::math::mobius;
    using m1une::math::prime_factorize;

    assert(is_prime(2));
    assert(is_prime(18446744073709551557ULL));
    assert(!is_prime(341550071728321ULL));

    const uint64_t semiprime = 1000000007ULL * 1000000009ULL;
    const auto factors = prime_factorize(semiprime);
    assert(factors.size() == 2);
    assert((factors[0] == std::pair<uint64_t, int>(1000000007ULL, 1)));
    assert((factors[1] == std::pair<uint64_t, int>(1000000009ULL, 1)));

    const std::vector<uint64_t> expected_divisors = {1, 2, 3, 4, 6, 9, 12, 18, 36};
    assert(divisors(36) == expected_divisors);
    assert(euler_phi(36) == 12);
    assert(mobius(30) == -1);
    assert(mobius(12) == 0);

    m1une::math::PrimeSieve sieve(10000);
    for (int value = 1; value <= sieve.limit(); value++) {
        const auto small_factors = sieve.factorize(value);
        const auto large_factors = prime_factorize(value);
        assert(small_factors.size() == large_factors.size());
        for (int i = 0; i < int(small_factors.size()); i++) {
            assert(uint64_t(small_factors[i].first) == large_factors[i].first);
            assert(small_factors[i].second == large_factors[i].second);
        }
    }
}

void test_primitive_root() {
    using m1une::math::euler_phi;
    using m1une::math::has_primitive_root;
    using m1une::math::primitive_root;

    assert(primitive_root(2) == 1);
    assert(primitive_root(4) == 3);
    assert(primitive_root(18) == 5);
    assert(primitive_root(998244353) == 3);
    assert(primitive_root(1000000007) == 5);
    assert(!has_primitive_root(8));
    assert(!has_primitive_root(12));
    assert(primitive_root(8) == 0);

    for (uint64_t mod = 2; mod <= 200; mod++) {
        const uint64_t root = primitive_root(mod);
        const uint64_t phi = euler_phi(mod);
        if (root == 0) {
            assert(!has_primitive_root(mod));
            bool found = false;
            for (uint64_t candidate = 1; candidate < mod; candidate++) {
                if (std::gcd(candidate, mod) != 1) continue;
                uint64_t value = 1;
                uint64_t order = 0;
                do {
                    value = value * candidate % mod;
                    order++;
                } while (value != 1);
                if (order == phi) found = true;
            }
            assert(!found);
            continue;
        }

        assert(has_primitive_root(mod));
        assert(std::gcd(root, mod) == 1);

        uint64_t value = 1;
        for (uint64_t exponent = 1; exponent < phi; exponent++) {
            value = value * root % mod;
            assert(value != 1);
        }
        value = value * root % mod;
        assert(value == 1);

        for (uint64_t candidate = 1; candidate < root; candidate++) {
            if (std::gcd(candidate, mod) != 1) continue;
            value = 1;
            uint64_t order = 0;
            do {
                value = value * candidate % mod;
                order++;
            } while (value != 1);
            assert(order != phi);
        }
    }
}

void test_totient_sum() {
    using m1une::math::totient_sum;
    using m1une::math::TotientSum;

    TotientSum solver(100);
    assert(solver.precalculation_limit() == 100);
    assert(solver.prefix_sum(0) == 0);
    assert(solver.prefix_sum(1) == 1);
    assert(solver(10) == 32);
    assert(totient_sum(100, 10) == 3044);

    m1une::math::PrimeSieve sieve(20000);
    const std::vector<int> phi = sieve.totient_table();
    __uint128_t expected = 0;
    for (int value = 1; value <= 20000; value++) {
        expected += static_cast<uint64_t>(phi[value]);
        assert(solver.prefix_sum(value) == expected);
    }

    for (uint64_t n : std::vector<uint64_t>{1, 2, 10, 100, 1000, 10000}) {
        __uint128_t left = 0;
        for (uint64_t q = 1; q <= n;) {
            const uint64_t quotient = n / q;
            const uint64_t next = n / quotient + 1;
            left += static_cast<__uint128_t>(next - q) * solver.prefix_sum(quotient);
            q = next;
        }
        const __uint128_t wide_n = n;
        assert(left == wide_n * (wide_n + 1) / 2);
    }
}

void test_combinatorics() {
    using Mint = m1une::math::modint998244353;
    m1une::math::Combinatorics<Mint> combinations(100);

    assert(combinations.factorial(5) == Mint(120));
    assert(combinations.inverse(5) * Mint(5) == Mint(1));
    assert(combinations.binom(10, 3) == Mint(120));
    assert(combinations.binom(3, 5) == Mint(0));
    assert(combinations.perm(5, 3) == Mint(60));
    assert(combinations.multiset(3, 4) == Mint(15));
    assert(combinations.multiset(0, 0) == Mint(1));
    assert(combinations.catalan(5) == Mint(42));

    assert(combinations.binom(100, 0) == Mint(1));
    assert(combinations.binom(100, 100) == Mint(1));
}

void test_combinatorial_sequences() {
    using Mint = m1une::math::modint998244353;

    const std::vector<Mint> catalan = m1une::math::catalan_numbers<Mint>(10);
    const std::vector<int> expected_catalan =
        {1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796};
    for (int i = 0; i <= 10; i++) assert(catalan[i] == Mint(expected_catalan[i]));
    m1une::math::Combinatorics<Mint> catalan_combinations(100);
    const std::vector<Mint> more_catalan =
        m1une::math::catalan_numbers<Mint>(50);
    for (int i = 0; i <= 50; i++) {
        assert(more_catalan[i] == catalan_combinations.catalan(i));
    }

    const std::vector<Mint> bernoulli = m1une::math::bernoulli_numbers<Mint>(20);
    assert(bernoulli[0] == Mint(1));
    assert(bernoulli[1] * Mint(2) == Mint(-1));
    assert(bernoulli[2] * Mint(6) == Mint(1));
    assert(bernoulli[4] * Mint(30) == Mint(-1));
    assert(bernoulli[6] * Mint(42) == Mint(1));
    for (int i = 3; i <= 19; i += 2) assert(bernoulli[i] == Mint(0));

    m1une::math::Combinatorics<Mint> combinations(21);
    for (int n = 1; n <= 20; n++) {
        Mint sum = 0;
        for (int k = 0; k <= n; k++) {
            sum += combinations.binom(n + 1, k) * bernoulli[k];
        }
        assert(sum == Mint(0));
    }

    const std::vector<Mint> bell = m1une::math::bell_numbers<Mint>(10);
    const std::vector<int> expected_bell =
        {1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975};
    for (int i = 0; i <= 10; i++) assert(bell[i] == Mint(expected_bell[i]));

    const std::vector<Mint> stirling_zero =
        m1une::math::stirling_numbers_second_kind<Mint>(0);
    assert(stirling_zero == std::vector<Mint>{Mint(1)});
    const std::vector<Mint> stirling =
        m1une::math::stirling_numbers_second_kind<Mint>(5);
    const std::vector<int> expected_stirling = {0, 1, 15, 25, 10, 1};
    for (int i = 0; i <= 5; i++) {
        assert(stirling[i] == Mint(expected_stirling[i]));
    }
    std::vector<Mint> stirling_dp(1, Mint(1));
    const std::vector<Mint> more_bell = m1une::math::bell_numbers<Mint>(30);
    for (int n = 0; n <= 30; n++) {
        if (n > 0) {
            std::vector<Mint> next(n + 1);
            for (int k = 1; k <= n; k++) {
                next[k] = stirling_dp[k - 1];
                if (k < int(stirling_dp.size())) {
                    next[k] += Mint(k) * stirling_dp[k];
                }
            }
            stirling_dp = std::move(next);
        }
        const std::vector<Mint> row =
            m1une::math::stirling_numbers_second_kind<Mint>(n);
        assert(row == stirling_dp);
        Mint sum = 0;
        for (Mint value : row) sum += value;
        assert(sum == more_bell[n]);
    }

    const std::vector<Mint> partitions = m1une::math::partition_numbers<Mint>(100);
    const std::vector<int> expected_partitions =
        {1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42};
    for (int i = 0; i <= 10; i++) {
        assert(partitions[i] == Mint(expected_partitions[i]));
    }
    std::vector<Mint> partition_dp(101);
    partition_dp[0] = 1;
    for (int part = 1; part <= 100; part++) {
        for (int sum = part; sum <= 100; sum++) {
            partition_dp[sum] += partition_dp[sum - part];
        }
    }
    assert(partitions == partition_dp);

    const std::vector<Mint> derangements =
        m1une::math::derangement_numbers<Mint>(10);
    const std::vector<int> expected_derangements =
        {1, 0, 1, 2, 9, 44, 265, 1854, 14833, 133496, 1334961};
    for (int i = 0; i <= 10; i++) {
        assert(derangements[i] == Mint(expected_derangements[i]));
    }
    m1une::math::Combinatorics<Mint> derangement_combinations(30);
    const std::vector<Mint> more_derangements =
        m1une::math::derangement_numbers<Mint>(30);
    Mint alternating_sum = 1;
    for (int n = 0; n <= 30; n++) {
        if (n > 0) {
            const Mint term = derangement_combinations.inverse_factorial(n);
            alternating_sum += (n & 1) ? Mint(0) - term : term;
        }
        assert(
            more_derangements[n] ==
            derangement_combinations.factorial(n) * alternating_sum
        );
    }
}

int main() {
    m1une::utilities::FastInput fast_input;
    m1une::utilities::FastOutput fast_output;

    test_number_theory();
    test_prime_sieve();
    test_large_factorization();
    test_primitive_root();
    test_totient_sum();
    test_combinatorics();
    test_combinatorial_sequences();

    long long a, b;
    fast_input >> a >> b;
    fast_output << a + b << '\n';
}
Back to top page