結果

問題 No.3030 ミラー・ラビン素数判定法のテスト
ユーザー sortA0329sortA0329
提出日時 2024-03-09 07:15:26
言語 C++23
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 32 ms / 9,973 ms
コード長 46,846 bytes
コンパイル時間 5,975 ms
コンパイル使用メモリ 442,188 KB
実行使用メモリ 6,820 KB
最終ジャッジ日時 2024-09-29 21:10:48
合計ジャッジ時間 6,660 ms
ジャッジサーバーID
(参考情報)
judge5 / judge2
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 2 ms
6,816 KB
testcase_02 AC 2 ms
6,816 KB
testcase_03 AC 1 ms
6,816 KB
testcase_04 AC 17 ms
6,820 KB
testcase_05 AC 18 ms
6,816 KB
testcase_06 AC 10 ms
6,816 KB
testcase_07 AC 9 ms
6,820 KB
testcase_08 AC 9 ms
6,816 KB
testcase_09 AC 32 ms
6,816 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize("O3")
#pragma GCC optimize("fast-math")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("avx")
#pragma GCC target("avx2")
#include <bits/stdc++.h>
using namespace std;
using i8 = std::int8_t;
using u8 = std::uint8_t;
using i16 = std::int16_t;
using u16 = std::uint16_t;
using i32 = std::int32_t;
using u32 = std::uint32_t;
using i64 = std::int64_t;
using u64 = std::uint64_t;
using i128 = __int128_t;
using u128 = __uint128_t;
using ll = long long;
using ull = unsigned long long;
using fl = float;
using db = double;
using ld = long double;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;
using vi = std::vector<int>;
using vll = std::vector<long long>;
using vvi = std::vector<std::vector<int>>;
using vvll = std::vector<std::vector<long long>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vvvll = std::vector<std::vector<std::vector<long long>>>;
using vvvvi = std::vector<std::vector<std::vector<std::vector<int>>>>;
using vvvvll = std::vector<std::vector<std::vector<std::vector<long long>>>>;
using vb = std::basic_string<bool>;
using vvb = std::vector<std::basic_string<bool>>;
using vvvb = std::vector<std::vector<std::basic_string<bool>>>;
using vstr = std::vector<std::string>;
using vvstr = std::vector<std::vector<std::string>>;
using vvvstr = std::vector<std::vector<std::vector<std::string>>>;
using vpii = std::vector<std::pair<int, int>>;
using vpll = std::vector<std::pair<long long, long long>>;
using vvpii = std::vector<std::vector<std::pair<int, int>>>;
using vvpll = std::vector<std::vector<std::pair<long long, long long>>>;
using vvvpii = std::vector<std::vector<std::vector<std::pair<int, int>>>>;
using vvvpll = std::vector<std::vector<std::vector<std::pair<long long, long long>>>>;
using seti = std::set<int>;
using setll = std::set<long long>;
using vseti = std::vector<std::set<int>>;
using vsetll = std::vector<std::set<long long>>;
using vvseti = std::vector<std::vector<std::set<int>>>;
using vvsetll = std::vector<std::vector<std::set<long long>>>;
using mapii = std::map<int, int>;
using mapll = std::map<long long, long long>;
using vmapii = std::vector<std::map<int, int>>;
using vmapll = std::vector<std::map<long long, long long>>;
using vvmapii = std::vector<std::vector<std::map<int, int>>>;
using vvmapll = std::vector<std::vector<std::map<long long, long long>>>;
template<class T> using vec = std::vector<T>;
template<class T> using vec2 = std::vector<std::vector<T>>;
template<class T> using vec3 = std::vector<std::vector<std::vector<T>>>;
template<class T> using vec4 = std::vector<std::vector<std::vector<std::vector<T>>>>;
template<class T> using maxheap = std::priority_queue<T, std::vector<T>, std::less<T>>;
template<class T> using minheap = std::priority_queue<T, std::vector<T>, std::greater<T>>;

#define ALL(V)       std::begin(V), std::end(V)
#define RALL(V)      std::rbegin(V), std::rend(V)
#define ALLMID(V, n) std::begin(V), std::next(std::begin(V), n), std::end(V)
#define MIN(T)       (std::numeric_limits<T>::lowest())
#define MAX(T)       (std::numeric_limits<T>::max())
#define EXPR(...)    (([&]() __VA_ARGS__)())
#define LAMBDA(...)  ([&](const auto&... _args_) { return (__VA_ARGS__); })
#define ARG(idx)     (std::get<(idx)>(std::forward_as_tuple(_args_...)))

#if __cplusplus >= 202001U
#define REP_VAR_NAME(n)                   REP_VAR_NAME_(n)
#define REP_VAR_NAME_(n)                  variable_for_loop_##n
#define REP_OVERLOAD4(a, b, c, d, e, ...) e

#define REP1(N)              for ([[maybe_unused]] const auto REP_VAR_NAME(__LINE__) : std::views::iota(std::decay_t<decltype(N)>{}, N))
#define REP2(i, N)           for ([[maybe_unused]] const auto i : std::views::iota(std::decay_t<decltype(N)>{}, N))
#define REP3(i, A, B)        for ([[maybe_unused]] const auto i : std::views::iota(static_cast<std::common_type_t<decltype(A), decltype(B)>>(A), static_cast<std::common_type_t<decltype(A), decltype(B)>>(B)))
#define REP4(i, A, B, C)     for ([[maybe_unused]] std::common_type_t<decltype(A), decltype(B)> i = (A); std::less<decltype(i)>{}(i, (B)); i += (C))
#define REP1_REV(N)          for ([[maybe_unused]] const auto REP_VAR_NAME(__LINE__) : std::views::iota(std::decay_t<decltype(N)>{}, N) | std::views::reverse)
#define REP2_REV(i, N)       for ([[maybe_unused]] const auto i : std::views::iota(std::decay_t<decltype(N)>{}, N) | std::views::reverse)
#define REP3_REV(i, A, B)    for ([[maybe_unused]] const auto i : std::views::iota(static_cast<std::common_type_t<decltype(A), decltype(B)>>(A), static_cast<std::common_type_t<decltype(A), decltype(B)>>(B)) | std::views::reverse)
#define REP4_REV(i, A, B, C) for ([[maybe_unused]] std::common_type_t<decltype(A), decltype(B)> i = (B) -1; std::less<decltype(i)>{}((A) -1, i); i -= (C))
#define rep(...)             REP_OVERLOAD4(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)
#define rrep(...)            REP_OVERLOAD4(__VA_ARGS__, REP4_REV, REP3_REV, REP2_REV, REP1_REV)(__VA_ARGS__)
#if __GNUC__ >= 12
#define repin(T, i, N) for ([[maybe_unused]] const auto i : std::views::istream<std::decay_t<T>>(std::cin) | std::views::take(N))
#endif
#else
#define rep(i, N)       for ([[maybe_unused]] auto i = std::decay_t<decltype(N)>{ 0 }; i != (N); ++i)
#define rrep(i, N)      for ([[maybe_unused]] auto i = (N) -1; i != -1; --i)
#define range(i, A, B)  for ([[maybe_unused]] auto i = (A); i != (B); ++i)
#define rrange(i, A, B) for ([[maybe_unused]] auto i = (B) -1; i != (A) -1; --i)
#endif
#include <unistd.h>
#include <immintrin.h>
// Thanks for https://zenn.dev/mizar/articles/fc87d667153080
class FastIstream : public std::ios_base {
    constexpr static int buffersize = (1 << 18) - 1;
    char buffer[buffersize + 1];
    char* cur = buffer;
    char* eof = buffer;
    inline void reload(ptrdiff_t w) {
        if (eof - w < cur) [[unlikely]] {
            if (eof == buffer + buffersize) [[likely]] {
                ptrdiff_t rem = eof - cur;
                std::memcpy(buffer, cur, rem);
                *(eof = buffer + rem + read(0, buffer + rem, buffersize - rem)) = '\0';
                cur = buffer;
            } else if (eof <= cur) {
                *(eof = buffer + read(0, buffer, buffersize)) = '\0';
                cur = buffer;
            }
        }
    }
public:
    FastIstream& operator>>(bool& n) {
        reload(2);
        n = *cur == '1';
        cur += 2;
        return *this;
    }
    FastIstream& operator>>(short& n) {
        reload(8);
        short neg = (*cur == '-') * -2 + 1;
        cur += neg == -1;
        uint64_t tmp = *(uint64_t*) cur ^ 0x3030303030303030u;
        int clz = std::countl_zero((tmp & 0x1010101010101010u) & (-(tmp & 0x1010101010101010u))) + 5;
        cur += (72 - clz) >> 3;
        tmp = ((tmp << clz) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
        tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
        n = (short) ((tmp * 0x271000000001ull) >> 32) * neg;
        return *this;
    }
    FastIstream& operator>>(unsigned short& n) {
        reload(8);
        uint64_t tmp = *(uint64_t*) cur ^ 0x3030303030303030u;
        int clz = std::countl_zero((tmp & 0x1010101010101010u) & (-(tmp & 0x1010101010101010u))) + 5;
        cur += (72 - clz) >> 3;
        tmp = ((tmp << clz) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
        tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
        n = (unsigned short) ((tmp * 0x271000000001ull) >> 32);
        return *this;
    }
    FastIstream& operator>>(unsigned int& n) {
        reload(16);
        uint64_t tmp = *(uint64_t*) cur ^ 0x3030303030303030u, tmp2 = tmp & 0x1010101010101010u;
        if (tmp2) {
            int clz = std::countl_zero(tmp2 & -tmp2) + 5;
            cur += (72 - clz) >> 3;
            tmp = ((tmp << clz) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
            tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
            n = (unsigned) ((tmp * 0x271000000001ull) >> 32);
        } else {
            cur += 8;
            tmp = (tmp * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
            tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
            n = (unsigned) ((tmp * 0x271000000001ull) >> 32);
            if (char c = *(cur++); c >= '0') {
                n = 10 * n + (c - '0');
                if ((c = *(cur++)) >= '0') n = 10 * n + (c - '0'), ++cur;
            }
        }
        return *this;
    }
    FastIstream& operator>>(int& n) {
        reload(16);
        int neg = (*cur == '-') * -2 + 1;
        cur += neg == -1;
        uint64_t tmp = *(uint64_t*) cur ^ 0x3030303030303030u, tmp2 = tmp & 0x1010101010101010u;
        if (tmp2) {
            int clz = std::countl_zero(tmp2 & -tmp2) + 5;
            cur += (72 - clz) >> 3;
            tmp = ((tmp << clz) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
            tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
            n = (int) ((tmp * 0x271000000001ull) >> 32);
        } else {
            cur += 8;
            tmp = (tmp * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull;
            tmp = (tmp * 0x640001ull) >> 16 & 0x0000ffff0000ffffull;
            n = (int) ((tmp * 0x271000000001ull) >> 32);
            if (char c = *(cur++); c >= '0') {
                n = 10 * n + (c - '0');
                if ((c = *(cur++)) >= '0') n = 10 * n + (c - '0'), ++cur;
            }
        }
        n *= neg;
        return *this;
    }
    FastIstream& operator>>(unsigned long long& n) {
        reload(32);
#ifndef __AVX512VL__
        n = 0;
        while (*cur >= '0') n = 10 * n + (*(cur++) - '0');
        ++cur;
#else
        unsigned long long tmp[3], tmp2[3];
        std::memcpy(tmp, cur, 24);
        int width;
        if ((tmp2[0] = (tmp[0] ^= 0x3030303030303030) & 0x1010101010101010)) [[unlikely]] {
            width = std::countr_zero(tmp2[0]) - 4;
            n = ((((((tmp[0] << (64 - width)) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull) * 0x640001ull) >> 16 & 0x0000ffff0000ffffull) * 0x271000000001ull) >> 32;
            cur += (width >> 3) + 1;
        } else {
            __m256i tmp3;
            if ((tmp2[1] = (tmp[1] ^= 0x3030303030303030) & 0x1010101010101010)) [[unlikely]] {
                width = 60 + std::countr_zero(tmp2[1]);
                if (width == 64) [[unlikely]]
                    tmp3 = _mm256_setr_epi64x(0, 0, 0, tmp[0]);
                else tmp3 = _mm256_setr_epi64x(0, 0, tmp[0] << (128 - width), tmp[1] << (128 - width) | tmp[0] >> (width - 64));
            } else {
                width = 124 + std::countr_zero((tmp[2] ^= 0x3030303030303030) & 0x1010101010101010);
                if (width == 128) [[unlikely]]
                    tmp3 = _mm256_setr_epi64x(0, 0, tmp[0], tmp[1]);
                else tmp3 = _mm256_setr_epi64x(0, tmp[0] << (192 - width), tmp[1] << (192 - width) | tmp[0] >> (width - 128), tmp[2] << (192 - width) | tmp[1] >> (width - 128));
            }
            cur += (width >> 3) + 1;
            alignas(32) unsigned long long res[4];
            _mm256_store_epi64(res, _mm256_srli_epi64(_mm256_mullo_epi64(_mm256_srli_epi32(_mm256_mullo_epi32(_mm256_srli_epi16(_mm256_mullo_epi16(_mm256_and_si256(tmp3, _mm256_set1_epi8(0x0f)), _mm256_set1_epi16(0xa01)), 8), _mm256_set1_epi32(0x640001)), 16), _mm256_set1_epi64x(0x271000000001)), 32));
            n = res[1] * 10000000000000000 + res[2] * 100000000 + res[3];
        }
#endif
        return *this;
    }
    FastIstream& operator>>(long long& n) {
        reload(32);
        long long neg = (*cur == '-') * -2 + 1;
        cur += neg == -1;
#ifndef __AVX512VL__
        n = 0;
        while (*cur >= '0') n = 10 * n + (*(cur++) - '0');
        ++cur;
        n *= neg;
#else
        unsigned long long tmp[3], tmp2[3];
        std::memcpy(tmp, cur, 24);
        int width;
        if ((tmp2[0] = (tmp[0] ^= 0x3030303030303030) & 0x1010101010101010)) [[unlikely]] {
            width = std::countr_zero(tmp2[0]) - 4;
            n = neg * (((((((tmp[0] << (64 - width)) * 0xa01ull) >> 8 & 0x00ff00ff00ff00ffull) * 0x640001ull) >> 16 & 0x0000ffff0000ffffull) * 0x271000000001ull) >> 32);
            cur += (width >> 3) + 1;
        } else {
            __m256i tmp3;
            if ((tmp2[1] = (tmp[1] ^= 0x3030303030303030) & 0x1010101010101010)) [[unlikely]] {
                width = 60 + std::countr_zero(tmp2[1]);
                if (width == 64) [[unlikely]]
                    tmp3 = _mm256_setr_epi64x(0, 0, 0, tmp[0]);
                else tmp3 = _mm256_setr_epi64x(0, 0, tmp[0] << (128 - width), tmp[1] << (128 - width) | tmp[0] >> (width - 64));
            } else {
                width = 124 + std::countr_zero((tmp[2] ^= 0x3030303030303030) & 0x1010101010101010);
                if (width == 128) [[unlikely]]
                    tmp3 = _mm256_setr_epi64x(0, 0, tmp[0], tmp[1]);
                else tmp3 = _mm256_setr_epi64x(0, tmp[0] << (192 - width), tmp[1] << (192 - width) | tmp[0] >> (width - 128), tmp[2] << (192 - width) | tmp[1] >> (width - 128));
            }
            cur += (width >> 3) + 1;
            alignas(32) long long res[4];
            _mm256_store_epi64(res, _mm256_srli_epi64(_mm256_mullo_epi64(_mm256_srli_epi32(_mm256_mullo_epi32(_mm256_srli_epi16(_mm256_mullo_epi16(_mm256_and_si256(tmp3, _mm256_set1_epi8(0x0f)), _mm256_set1_epi16(0xa01)), 8), _mm256_set1_epi32(0x640001)), 16), _mm256_set1_epi64x(0x271000000001)), 32));
            n = neg * (res[1] * 10000000000000000 + res[2] * 100000000 + res[3]);
        }
#endif
        return *this;
    }
    FastIstream& operator>>(long& n) {
        long long x;
        operator>>(x);
        n = x;
        return *this;
    }
    FastIstream& operator>>(unsigned long& n) {
        unsigned long long x;
        operator>>(x);
        n = x;
        return *this;
    }
    friend FastIstream& operator>>(FastIstream& is, char& c) {
        is.reload(2);
        c = *is.cur;
        is.cur += 2;
        return is;
    }
    friend FastIstream& operator>>(FastIstream& is, unsigned char& c) {
        is.reload(2);
        c = *is.cur;
        is.cur += 2;
        return is;
    }
    friend FastIstream& operator>>(FastIstream& is, signed char& c) {
        is.reload(2);
        c = *is.cur;
        is.cur += 2;
        return is;
    }
    friend FastIstream& operator>>(FastIstream& is, char* s) {
        while (true) {
            while (*is.cur > ' ' && is.cur != is.eof) *(s++) = *is.cur, ++is.cur;
            if (is.cur == is.eof) is.reload(is.buffersize);
            else break;
        }
        ++is.cur;
        *s = '\0';
        return is;
    }
    friend FastIstream& operator>>(FastIstream& is, std::string& s) {
        s.clear();
        while (true) {
            char* st = is.cur;
            while (*is.cur > ' ' && is.cur != is.eof) ++is.cur;
            s += std::string_view(st, is.cur - st);
            if (is.cur == is.eof) is.reload(is.buffersize);
            else break;
        }
        ++is.cur;
        return is;
    }
    FastIstream& operator>>(float& f) {
        std::string s;
        (*this) >> s;
        std::from_chars(s.c_str(), s.c_str() + s.length(), f);
        return *this;
    }
    FastIstream& operator>>(double& f) {
        std::string s;
        (*this) >> s;
        std::from_chars(s.c_str(), s.c_str() + s.length(), f);
        return *this;
    }
    FastIstream& operator>>(long double& f) {
        std::string s;
        (*this) >> s;
        std::from_chars(s.c_str(), s.c_str() + s.length(), f);
        return *this;
    }
    template<std::ranges::range T> friend FastIstream& operator>>(FastIstream& is, T& x) {
        for (auto& v : x) is >> v;
        return is;
    }
} fin;
class FastOstream : public std::ios_base {
    constexpr static int buffersize = 1 << 18;
    char buffer[buffersize];
    char* cur = buffer;
    inline void reload(ptrdiff_t w) {
        if (buffer + buffersize - w < cur) [[unlikely]] {
            [[maybe_unused]] int r = write(1, buffer, cur - buffer);
            cur = buffer;
        }
    }
    constexpr static std::array<unsigned, 10000> strtable = []() {
        std::array<unsigned, 10000> res;
        for (unsigned i = 0; i < 10000; ++i) {
            unsigned tmp[4];
            unsigned n = i;
            tmp[3] = (n % 10 + '0') << 24, n /= 10;
            tmp[2] = (n % 10 + '0') << 16, n /= 10;
            tmp[1] = (n % 10 + '0') << 8, n /= 10;
            tmp[0] = n % 10 + '0';
            res[i] = tmp[0] + tmp[1] + tmp[2] + tmp[3];
        }
        return res;
    }();
    constexpr static std::array<unsigned, 10000> strtable2 = []() {
        std::array<unsigned, 10000> res;
        for (unsigned i = 0; i < 10000; ++i) {
            unsigned tmp[4];
            unsigned n = i;
            if (i < 10) n *= 1000;
            else if (i < 100) n *= 100;
            else if (i < 1000) n *= 10;
            tmp[3] = (n % 10 + '0') << 24, n /= 10;
            tmp[2] = (n % 10 + '0') << 16, n /= 10;
            tmp[1] = (n % 10 + '0') << 8, n /= 10;
            tmp[0] = n % 10 + '0';
            res[i] = tmp[0] + tmp[1] + tmp[2] + tmp[3];
        }
        return res;
    }();
    template<class T> void putfloat(T f) {
        bool fixed = flags() & std::ios_base::fixed;
        bool scientific = flags() & std::ios_base::scientific;
        bool uppercase = flags() & std::ios_base::uppercase;
        if (fixed && scientific && (flags() & std::ios_base::showbase)) {
            std::memcpy(cur, (uppercase ? "0X" : "0x"), 2);
            cur += 2;
        }
        std::chars_format fmt = (fixed ? (scientific ? std::chars_format::hex : std::chars_format::fixed) : (scientific ? std::chars_format::scientific : std::chars_format::general));
        auto conv = [&]() {
            return std::to_chars(cur, buffer + buffersize, f, fmt, precision());
        };
        auto [ptr, ec] = conv();
        char* p;
        if (ec == std::errc::value_too_large) {
            reload(buffersize);
            p = cur;
            cur = conv().ptr;
        } else p = cur, cur = ptr;
        if (uppercase) {
            while (p != cur) {
                if (*p > '9') *p -= ('a' - 'A');
                ++p;
            }
        }
    }
public:
    FastOstream() {
        precision(6);
        setf(std::ios_base::showbase);
    }
    ~FastOstream() { reload(buffersize); }
    FastOstream& flush() {
        reload(buffersize);
        return *this;
    }
    char widen(char c) const { return c; }
    FastOstream& put(char c) {
        reload(1);
        *(cur++) = c;
        return *this;
    }
    FastOstream& operator<<(std::basic_ostream<FastOstream, void>& (*pf)(std::basic_ostream<FastOstream, void>&) );
    FastOstream& operator<<(std::basic_ios<FastOstream, void>& (*pf)(std::basic_ios<FastOstream, void>&) );
    FastOstream& operator<<(std::ios_base& (*pf)(std::ios_base&) ) {
        pf(*this);
        return *this;
    }
    FastOstream& operator<<(bool n) {
        if (ios_base::flags() & std::ios_base::boolalpha) {
            if (n) {
                reload(4);
                std::memcpy(cur, "true", 4);
                cur += 4;
            } else {
                reload(5);
                std::memcpy(cur, "false", 5);
                cur += 5;
            }
        } else {
            reload(1);
            *(cur++) = '0' + n;
        }
        return *this;
    }
    FastOstream& operator<<(unsigned short n) {
        reload(5);
        if (n >= 10000) {
            *(cur++) = '0' + n / 10000, n %= 10000;
            *reinterpret_cast<unsigned*>(cur) = strtable[n];
            cur += 4;
        } else if (n >= 1000) {
            *reinterpret_cast<unsigned*>(cur) = strtable[n];
            cur += 4;
        } else if (n >= 100) {
            *reinterpret_cast<unsigned*>(cur) = strtable[n * 10];
            cur += 3;
        } else if (n >= 10) {
            *(cur++) = '0' + n / 10;
            *(cur++) = '0' + n % 10;
        } else *(cur++) = '0' + n;
        return *this;
    }
    FastOstream& operator<<(short n) {
        reload(6);
        if (n < 0) *(cur++) = '-', n = -n;
        if (n >= 10000) {
            *(cur++) = '0' + n / 10000, n %= 10000;
            *reinterpret_cast<unsigned*>(cur) = strtable[n];
            cur += 4;
        } else if (n >= 1000) {
            *reinterpret_cast<unsigned*>(cur) = strtable[n];
            cur += 4;
        } else if (n >= 100) {
            *reinterpret_cast<unsigned*>(cur) = strtable[n * 10];
            cur += 3;
        } else if (n >= 10) {
            *reinterpret_cast<unsigned*>(cur) = strtable[n * 100];
            cur += 2;
        } else *(cur++) = '0' + n;
        return *this;
    }
    FastOstream& operator<<(unsigned n) {
        reload(10);
        unsigned long long buf = 0;
        char d = 0;
        if (n >= 100000000) {
            d = 8;
            buf = static_cast<unsigned long long>(strtable[n % 10000]) << 32 | strtable[(n / 10000) % 10000];
            n /= 100000000;
        } else if (n >= 10000) {
            d = 4;
            buf = strtable[n % 10000];
            n /= 10000;
        }
        *reinterpret_cast<unsigned*>(cur) = strtable2[n];
        cur += (n >= 10) + (n >= 100) + (n >= 1000) + 1;
        *reinterpret_cast<unsigned long long*>(cur) = buf;
        cur += d;
        return *this;
    }
    FastOstream& operator<<(int n) {
        reload(11);
        if (n < 0) *(cur++) = '-', n = -n;
        unsigned long long buf = 0;
        char d = 0;
        if (n >= 100000000) {
            d = 8;
            buf = static_cast<unsigned long long>(strtable[n % 10000]) << 32 | strtable[(n / 10000) % 10000];
            n /= 100000000;
        } else if (n >= 10000) {
            d = 4;
            buf = strtable[n % 10000];
            n /= 10000;
        }
        *reinterpret_cast<unsigned*>(cur) = strtable2[n];
        cur += (n >= 10) + (n >= 100) + (n >= 1000) + 1;
        *reinterpret_cast<unsigned long long*>(cur) = buf;
        cur += d;
        return *this;
    }
    FastOstream& operator<<(unsigned long long n) {
        reload(20);
        static unsigned buf[4];
        int d = 0;
        if (n >= 10000000000000000) {
            d = 16;
            buf[3] = strtable[n % 10000], n /= 10000;
            buf[2] = strtable[n % 10000], n /= 10000;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 1000000000000) {
            d = 12;
            buf[2] = strtable[n % 10000], n /= 10000;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 100000000) {
            d = 8;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 10000) {
            d = 4;
            buf[0] = strtable[n % 10000], n /= 10000;
        }
        *(unsigned*) cur = strtable2[n];
        cur += (n >= 10) + (n >= 100) + (n >= 1000) + 1;
        std::memcpy(cur, buf, d);
        cur += d;
        return *this;
    }
    FastOstream& operator<<(long long n) {
        reload(21);
        if (n < 0) *(cur++) = '-', n = -n;
        static unsigned buf[4];
        char d = 0;
        if (n >= 10000000000000000) {
            d = 16;
            buf[3] = strtable[n % 10000], n /= 10000;
            buf[2] = strtable[n % 10000], n /= 10000;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 1000000000000) {
            d = 12;
            buf[2] = strtable[n % 10000], n /= 10000;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 100000000) {
            d = 8;
            buf[1] = strtable[n % 10000], n /= 10000;
            buf[0] = strtable[n % 10000], n /= 10000;
        } else if (n >= 10000) {
            d = 4;
            buf[0] = strtable[n % 10000], n /= 10000;
        }
        *(unsigned*) cur = strtable2[n];
        cur += (n >= 10) + (n >= 100) + (n >= 1000) + 1;
        std::memcpy(cur, buf, d);
        cur += d;
        return *this;
    }
    FastOstream& operator<<(long n) { return operator<<(static_cast<long long>(n)); }
    FastOstream& operator<<(unsigned long n) { return operator<<(static_cast<unsigned long long>(n)); }
    FastOstream& operator<<(float f) {
        reload(16);
        putfloat(f);
        return *this;
    }
    FastOstream& operator<<(double f) {
        reload(32);
        putfloat(f);
        return *this;
    }
    FastOstream& operator<<(long double f) {
        reload(64);
        putfloat(f);
        return *this;
    }
    FastOstream& operator<<(const void* p) {
        reload(18);
        if (flags() & std::ios_base::showbase) {
            *cur = '0';
            *(cur + 1) = flags() & std::ios_base::uppercase ? 'X' : 'x';
            cur += 2;
        }
        cur = std::to_chars(cur, buffer + buffersize, reinterpret_cast<unsigned long long>(p), 16).ptr;
        return *this;
    }
    FastOstream& operator<<(std::nullptr_t) {
        reload(7);
        std::memcpy(cur, "nullptr", 7);
        cur += 7;
        return *this;
    }
    friend FastOstream& operator<<(FastOstream& os, char c) {
        os.reload(1);
        *(os.cur++) = c;
        return os;
    }
    friend FastOstream& operator<<(FastOstream& os, signed char c) {
        os.reload(1);
        *(os.cur++) = c;
        return os;
    }
    friend FastOstream& operator<<(FastOstream& os, unsigned char c) {
        os.reload(1);
        *(os.cur++) = c;
        return os;
    }
    friend FastOstream& operator<<(FastOstream& os, const char* s) {
        size_t n = std::strlen(s);
        if (n >= os.buffersize) {
            os.reload(buffersize);
            write(1, s, n);
        } else {
            os.reload(n);
            std::memcpy(os.cur, s, n);
            os.cur += n;
        }
        return os;
    }
    friend FastOstream& operator<<(FastOstream& os, const std::string& s) {
        size_t n = s.length();
        if (n >= os.buffersize) {
            os.reload(buffersize);
            write(1, s.data(), n);
        } else {
            os.reload(n);
            std::memcpy(os.cur, s.data(), n);
            os.cur += n;
        }
        return os;
    }
    friend FastOstream& operator<<(FastOstream& os, std::string_view s) {
        size_t n = s.length();
        if (n >= os.buffersize) {
            os.reload(buffersize);
            write(1, s.data(), n);
        } else {
            os.reload(n);
            std::memcpy(os.cur, s.data(), n);
            os.cur += n;
        }
        return os;
    }
    template<std::ranges::range T> friend FastOstream& operator<<(FastOstream& os, const T& v) {
        size_t n = std::distance(std::ranges::begin(v), std::ranges::end(v)), cnt = 0;
        for (const auto& x : v) {
            os << x;
            if (++cnt != n) os << ' ';
        }
        return os;
    }
#if __GNUC__ >= 6
    friend FastOstream& operator<<(FastOstream& os, std::_Setprecision prec) {
        os.precision(prec._M_n);
        return os;
    }
#endif
} fout;
namespace std {
template<> class basic_ios<FastOstream, void> {
protected:
    FastOstream& ref;
public:
    basic_ios(FastOstream& r) : ref(r) {}
    char widen(char c) { return ref.widen(c); }
};
template<> class basic_ostream<FastOstream, void> : public basic_ios<FastOstream, void> {
public:
    basic_ostream(FastOstream& r) : basic_ios(r) {}
    basic_ostream& put(char c) {
        basic_ios::ref.put(c);
        return *this;
    }
    basic_ostream& flush() {
        basic_ios::ref.flush();
        return *this;
    }
};
}  // namespace std
FastOstream& FastOstream::operator<<(std::basic_ostream<FastOstream, void>& (*pf)(std::basic_ostream<FastOstream, void>&) ) {
    std::basic_ostream<FastOstream, void> tmp(*this);
    pf(tmp);
    return *this;
}
FastOstream& FastOstream::operator<<(std::basic_ios<FastOstream, void>& (*pf)(std::basic_ios<FastOstream, void>&) ) {
    std::basic_ios<FastOstream, void> tmp(*this);
    pf(tmp);
    return *this;
}
template<class T> class ModintTraits : public T {
    using base_type = T;
public:
    using value_type = std::decay_t<decltype(base_type::mod())>;
    using modint_type = ModintTraits;
    constexpr static bool is_staticmod = !requires { base_type::set_mod(0); };
    constexpr ModintTraits() noexcept : T() {}
    template<class U> constexpr ModintTraits(U x) noexcept { operator=(x); }
    constexpr explicit operator value_type() const noexcept { return val(); }
    constexpr static void set_mod(value_type x) {
        static_assert(!is_staticmod, "ModintTraits::set_mod / Mod must be dynamic.");
        if (x <= 1) throw std::runtime_error("ModintTraits::set_mod / Mod must be at least 2.");
        if (x == mod()) return;
        base_type::set_mod(x);
    }
    constexpr value_type val() const noexcept { return base_type::val(); }
    constexpr static value_type mod() noexcept { return base_type::mod(); }
    template<class U> constexpr modint_type& operator=(U x) noexcept {
        static_assert(std::is_integral_v<U>, "ModintTraits::operator= / Only integer types can be assigned.");
        if constexpr (std::is_unsigned_v<U>) {
            if constexpr (std::is_same_v<U, unsigned long long> || std::is_same_v<U, unsigned long>) base_type::assign(static_cast<std::uint64_t>(x));
            else base_type::assign(static_cast<std::uint32_t>(x));
        } else {
            if (x < 0) {
                if constexpr (std::is_same_v<U, long long> || std::is_same_v<U, long>) base_type::assign(static_cast<std::uint64_t>(-x));
                else base_type::assign(static_cast<std::uint32_t>(-x));
                base_type::neg();
            } else {
                if constexpr (std::is_same_v<U, long long> || std::is_same_v<U, long>) base_type::assign(static_cast<std::uint64_t>(x));
                else base_type::assign(static_cast<std::uint32_t>(x));
            }
        }
        return *this;
    }
    constexpr static modint_type raw(value_type x) noexcept {
        modint_type res;
        res.rawassign(x);
        return res;
    }
    template<class Istream> friend Istream& operator>>(Istream& ist, modint_type& x) {
        value_type n;
        ist >> n;
        x = n;
        return ist;
    }
    template<class Ostream> friend Ostream& operator<<(Ostream& ost, modint_type x) { return ost << x.val(); }
    constexpr modint_type inv() const {
        value_type a = 1, b = 0, x = val(), y = mod();
        if (x == 0) throw std::runtime_error("ModintTraits::inv / Zero division is not possible.");
        while (true) {
            if (x <= 1) {
                if (x == 0) [[unlikely]]
                    break;
                else return modint_type::raw(a);
            }
            b += a * (y / x);
            y %= x;
            if (y <= 1) {
                if (y == 0) [[unlikely]]
                    break;
                else return modint_type::raw(mod() - b);
            }
            a += b * (x / y);
            x %= y;
        }
        throw std::runtime_error("ModintTraits::inv / Cannot calculate inverse element.");
    }
    constexpr modint_type pow(uint64_t e) const noexcept {
        modint_type res = modint_type::raw(1), pow = *this;
        while (e) {
            modint_type tmp = pow * pow;
            if (e & 1) res *= pow;
            pow = tmp;
            e >>= 1;
        }
        return res;
    }
    constexpr modint_type operator+() const noexcept { return *this; }
    constexpr modint_type operator-() const noexcept {
        modint_type res = *this;
        res.neg();
        return res;
    }
    constexpr modint_type& operator++() noexcept {
        base_type::inc();
        return *this;
    }
    constexpr modint_type& operator--() noexcept {
        base_type::dec();
        return *this;
    }
    constexpr modint_type operator++(int) noexcept {
        modint_type copy = *this;
        operator++();
        return copy;
    }
    constexpr modint_type operator--(int) noexcept {
        modint_type copy = *this;
        operator--();
        return copy;
    }
    constexpr modint_type& operator+=(modint_type x) noexcept {
        base_type::add(x);
        return *this;
    }
    constexpr modint_type& operator-=(modint_type x) noexcept {
        base_type::sub(x);
        return *this;
    }
    constexpr modint_type& operator*=(modint_type x) noexcept {
        base_type::mul(x);
        return *this;
    }
    constexpr modint_type& operator/=(modint_type x) {
        operator*=(x.inv());
        return *this;
    }
    friend constexpr modint_type operator+(modint_type l, modint_type r) noexcept { return modint_type(l) += r; }
    friend constexpr modint_type operator-(modint_type l, modint_type r) noexcept { return modint_type(l) -= r; }
    friend constexpr modint_type operator*(modint_type l, modint_type r) noexcept { return modint_type(l) *= r; }
    friend constexpr modint_type operator/(modint_type l, modint_type r) { return modint_type(l) /= r; }
    friend constexpr bool operator==(modint_type l, modint_type r) noexcept { return l.val() == r.val(); }
    friend constexpr bool operator!=(modint_type l, modint_type r) noexcept { return l.val() != r.val(); }
    constexpr int legendre() const noexcept {
        value_type res = pow((mod() - 1) >> 1).val();
        return (res <= 1 ? static_cast<int>(res) : -1);
    }
    constexpr int jacobi() const noexcept {
        value_type a = val(), n = mod();
        if (a == 1) return 1;
        if (std::gcd(a, n) != 1) return 0;
        int res = 1;
        while (a != 0) {
            while (!(a & 1) && a != 0) {
                a >>= 1;
                if ((n & 0b111) == 3 || (n & 0b111) == 5) res = -res;
            }
            if ((a & 0b11) == 3 || (n & 0b11) == 3) res = -res;
            std::swap(a, n);
            a %= n;
        }
        if (n != 1) return 0;
        return res;
    }
    constexpr modint_type sqrt() const noexcept {
        const value_type vl = val(), md = mod();
        if (vl <= 1) return *this;
        auto get_min = [](modint_type x) {
            return x.val() > (mod() >> 1) ? -x : x;
        };
        if ((md & 0b11) == 3) return get_min(pow((md + 1) >> 2));
        else if ((md & 0b111) == 5) {
            modint_type res = pow((md + 3) >> 3);
            if constexpr (is_staticmod) {
                constexpr modint_type p = modint_type::raw(2).pow((md - 1) >> 2);
                res *= p;
            } else if (res * res != *this) res *= modint_type::raw(2).pow((md - 1) >> 2);
            return get_min(res);
        } else {
            value_type Q = md - 1;
            uint32_t S = 0;
            while ((Q & 1) == 0) Q >>= 1, ++S;
            if (std::countr_zero(md - 1) < 6) {
                modint_type z = modint_type::raw(1);
                while (z.legendre() != -1) ++z;
                modint_type t = pow(Q), R = pow((Q + 1) / 2);
                if (t.val() == 1) return R;
                uint32_t M = S;
                modint_type c = z.pow(Q);
                do {
                    modint_type U = t * t;
                    uint32_t i = 1;
                    while (U.val() != 1) U = U * U, ++i;
                    modint_type b = c;
                    for (uint32_t j = 0; j < (M - i - 1); ++j) b *= b;
                    M = i, c = b * b, t *= c, R *= b;
                } while (t.val() != 1);
                return get_min(R);
            } else {
                modint_type a = 1;
                while ((a * a - *this).legendre() != -1) ++a;
                modint_type res1 = modint_type::raw(1), res2, pow1 = a, pow2 = modint_type::raw(1), w = a * a - *this;
                value_type e = (md + 1) / 2;
                while (true) {
                    if (e & 1) {
                        modint_type tmp = res1;
                        res1 = res1 * pow1 + res2 * pow2 * w;
                        res2 = tmp * pow2 + res2 * pow1;
                    }
                    e >>= 1;
                    if (e == 0) return get_min(res1);
                    modint_type tmp = pow1;
                    pow1 = pow1 * pow1 + pow2 * pow2 * w;
                    pow2 *= modint_type::raw(2) * tmp;
                }
            }
        }
    }
};
template<std::uint32_t mod_> class StaticModint32_impl {
    using value_type = std::uint32_t;
    using modint_type = StaticModint32_impl;
    value_type val_ = 0;
protected:
    constexpr StaticModint32_impl() noexcept {}
    constexpr value_type val() const noexcept { return val_; }
    static constexpr value_type mod() noexcept { return mod_; }
    constexpr void assign(std::uint32_t x) noexcept { val_ = x % mod_; }
    constexpr void assign(std::uint64_t x) noexcept { val_ = x % mod_; }
    constexpr void rawassign(value_type x) noexcept { val_ = x; }
    constexpr void neg() noexcept { val_ = (val_ == 0 ? 0 : mod_ - val_); }
    constexpr void inc() noexcept { val_ = (val_ == mod_ - 1 ? 0 : val_ + 1); }
    constexpr void dec() noexcept { val_ = (val_ == 0 ? mod_ - 1 : val_ - 1); }
    constexpr void add(modint_type x) noexcept {
        if (mod_ - val_ > x.val_) val_ += x.val_;
        else val_ = x.val_ - (mod_ - val_);
    }
    constexpr void sub(modint_type x) noexcept {
        if (val_ >= x.val_) val_ -= x.val_;
        else val_ = mod_ - (x.val_ - val_);
    }
    constexpr void mul(modint_type x) noexcept { val_ = static_cast<std::uint64_t>(val_) * x.val_ % mod_; }
};
template<std::uint32_t mod_ = 998244353> using StaticModint32 = ModintTraits<StaticModint32_impl<mod_>>;
template<std::uint64_t mod_> class StaticModint64_impl {
    using value_type = std::uint64_t;
    using modint_type = StaticModint64_impl;
    value_type val_ = 0;
protected:
    constexpr StaticModint64_impl() noexcept {}
    constexpr value_type val() const noexcept { return val_; }
    static constexpr value_type mod() noexcept { return mod_; }
    constexpr void assign(std::uint32_t x) noexcept {
        if constexpr (mod_ < (1ull << 32)) val_ = x % mod_;
        else val_ = x;
    }
    constexpr void assign(std::uint64_t x) noexcept { val_ = x % mod_; }
    constexpr void rawassign(value_type x) noexcept { val_ = x; }
    constexpr void neg() noexcept { val_ = (val_ == 0 ? 0 : mod_ - val_); }
    constexpr void inc() noexcept { val_ = (val_ == mod_ - 1 ? 0 : val_ + 1); }
    constexpr void dec() noexcept { val_ = (val_ == 0 ? mod_ - 1 : val_ - 1); }
    constexpr void add(modint_type x) noexcept {
        if (mod_ - val_ > x.val_) val_ += x.val_;
        else val_ = x.val_ - (mod_ - val_);
    }
    constexpr void sub(modint_type x) noexcept {
        if (val_ >= x.val_) val_ -= x.val_;
        else val_ = mod_ - (x.val_ - val_);
    }
    constexpr void mul(modint_type x) noexcept { val_ = static_cast<__uint128_t>(val_) * x.val_ % mod_; }
};
template<std::uint64_t mod_ = 998244353> using StaticModint64 = ModintTraits<StaticModint64_impl<mod_>>;
template<std::uint64_t mod_ = 998244353> using StaticModint = std::conditional_t<(mod_ < (1ull << 32)), StaticModint32<mod_>, StaticModint64<mod_>>;
template<int id> class DynamicModint32_impl {
    using value_type = std::uint32_t;
    using modint_type = DynamicModint32_impl;
    static inline value_type mod_ = 0;
    static inline std::uint64_t mod64_ = 0;
    static inline __uint128_t L_ = 0;
    value_type val_ = 0;
    value_type reduce(std::uint32_t c) const noexcept {
        std::uint32_t q = (c * L_) >> 96;
        return c - q * mod_;
    }
    value_type reduce(std::uint64_t c) const noexcept {
        std::uint64_t q = (c * L_) >> 96;
        return c - q * mod64_;
    }
protected:
    DynamicModint32_impl() noexcept {}
    static void set_mod(value_type newmod) noexcept {
        mod_ = newmod, mod64_ = newmod;
        L_ = ((__uint128_t(1) << 96) - 1) / mod_ + 1;
    }
    value_type val() const noexcept { return val_; }
    static value_type mod() noexcept { return mod_; }
    void assign(std::uint32_t x) noexcept { val_ = reduce(x); }
    void assign(std::uint64_t x) noexcept { val_ = reduce(x); }
    void rawassign(value_type x) noexcept { val_ = x; }
    void neg() noexcept { val_ = (val_ == 0 ? 0 : mod_ - val_); }
    void inc() noexcept { val_ = (val_ == mod_ - 1 ? 0 : val_ + 1); }
    void dec() noexcept { val_ = (val_ == 0 ? mod_ - 1 : val_ - 1); }
    void add(modint_type x) noexcept {
        if (mod_ - val_ > x.val_) val_ += x.val_;
        else val_ = x.val_ - (mod_ - val_);
    }
    void sub(modint_type x) noexcept {
        if (val_ >= x.val_) val_ -= x.val_;
        else val_ = mod_ - (x.val_ - val_);
    }
    void mul(modint_type x) noexcept { val_ = reduce(static_cast<std::uint64_t>(val_) * x.val_); }
};
template<int id = 0> using DynamicModint32 = ModintTraits<DynamicModint32_impl<id>>;
template<int id> class DynamicModint64_impl {
    using value_type = std::uint64_t;
    using modint_type = DynamicModint64_impl;
    static inline value_type mod_ = 0;
    static inline __uint128_t mod128_ = 0, M_ = 0;
    value_type val_ = 0;
protected:
    DynamicModint64_impl() noexcept {}
    static void set_mod(value_type newmod) noexcept {
        mod_ = newmod, mod128_ = mod_;
        M_ = std::numeric_limits<__uint128_t>::max() / mod_ + std::has_single_bit(mod_);
    }
    value_type val() const noexcept { return val_; }
    static value_type mod() noexcept { return mod_; }
    void assign(std::uint64_t x) noexcept { val_ = x % mod_; }
    void rawassign(value_type x) noexcept { val_ = x; }
    void neg() noexcept { val_ = (val_ == 0 ? 0 : mod_ - val_); }
    void inc() noexcept { val_ = (val_ == mod_ - 1 ? 0 : val_ + 1); }
    void dec() noexcept { val_ = (val_ == 0 ? mod_ - 1 : val_ - 1); }
    void add(modint_type x) noexcept {
        if (mod_ - val_ > x.val_) val_ += x.val_;
        else val_ = x.val_ - (mod_ - val_);
    }
    void sub(modint_type x) noexcept {
        if (val_ >= x.val_) val_ -= x.val_;
        else val_ = mod_ - (x.val_ - val_);
    }
    void mul(modint_type x) noexcept {
        std::uint64_t tmp = static_cast<__uint128_t>(val_) * x.val_ - ((((M_ * val_) >> 64) * x.val_) >> 64) * mod128_;
        val_ = (tmp < mod_ ? tmp : tmp - mod_);
    }
};
template<int id = 0> using DynamicModint64 = ModintTraits<DynamicModint64_impl<id>>;
template<class Modint> class ModManager {
    Modint::value_type prev;
public:
    ModManager() { prev = Modint::mod(); }
    ~ModManager() {
        if (prev != 0) Modint::set_mod(prev);
    }
    void set_mod(Modint::value_type newmod) { Modint::set_mod(newmod); }
};
template<bool trial_division = true> bool isPrime32(const std::uint32_t x) {
    if constexpr (trial_division) {
        if (x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0 || x % 11 == 0 || x % 13 == 0 || x % 17 == 0 || x % 19 == 0 || x % 23 == 0 || x % 29 == 0 || x % 31 == 0 || x % 37 == 0 || x % 41 == 0 || x % 43 == 0) return x <= 43 && (x == 2 || x == 3 || x == 5 || x == 7 || x == 11 || x == 13 || x == 17 || x == 19 || x == 23 || x == 29 || x == 31 || x == 37 || x == 41 || x == 43);
        if (x < 47 * 47) return (x > 1);
    } else {
        if (x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0) return x <= 7 && (x == 2 || x == 3 || x == 5 || x == 7);
        if (x < 11 * 11) return (x > 1);
    }
    constexpr std::uint16_t bases[] = { 15591, 2018,  166,  7429, 8064, 16045, 10503, 4399,  1949, 1295,  2776, 3620, 560,   3128, 5212, 2657, 2300, 2021, 4652, 1471, 9336,  4018, 2398,  20462, 10277, 8028,  2213, 6219,  620,  3763,  4852, 5012,  3185,  1333, 6227, 5298, 1074, 2391,  5113, 7061, 803,  1269, 3875, 422,   751,  580,   4729,  10239, 746,  2951, 556,  2206, 3778, 481,   1522, 3476, 481,  2487, 3266, 5633,  488,   3373,  6441,  3344,
                                        17,    15105, 1490, 4154, 2036, 1882,  1813,  467,   3307, 14042, 6371, 658,  1005,  903,  737,  1887, 7447, 1888, 2848, 1784, 7559,  3400, 951,   13969, 4304,  177,   41,   19875, 3110, 13221, 8726, 571,   7043,  6943, 1199, 352,  6435, 165,   1169, 3315, 978,  233,  3003, 2562,  2994, 10587, 10030, 2377,  1902, 5354, 4447, 1555, 263,  27027, 2283, 305,  669,  1912, 601,  6186,  429,   1930,  14873, 1784,
                                        1661,  524,   3577, 236,  2360, 6146,  2850,  55637, 1753, 4178,  8466, 222,  2579,  2743, 2031, 2226, 2276, 374,  2132, 813,  23788, 1610, 4422,  5159,  1725,  3597,  3366, 14336, 579,  165,   1375, 10018, 12616, 9816, 1371, 536,  1867, 10864, 857,  2206, 5788, 434,  8085, 17618, 727,  3639,  1595,  4944,  2129, 2029, 8195, 8344, 6232, 9183,  8126, 1870, 3296, 7455, 8947, 25017, 541,   19115, 368,   566,
                                        5674,  411,   522,  1027, 8215, 2050,  6544,  10049, 614,  774,   2333, 3007, 35201, 4706, 1152, 1785, 1028, 1540, 3743, 493,  4474,  2521, 26845, 8354,  864,   18915, 5465, 2447,  42,   4511,  1660, 166,   1249,  6259, 2553, 304,  272,  7286,  73,   6554, 899,  2816, 5197, 13330, 7054, 2818,  3199,  811,   922,  350,  7514, 4452, 3449, 2663,  4708, 418,  1621, 1171, 3471, 88,    11345, 412,   1559,  194 };
    using mint = DynamicModint32<-1>;
    mint::set_mod(x);
    std::uint64_t h = x;
    h = ((h >> 16) ^ h) * 0x45d9f3b;
    h = ((h >> 16) ^ h) * 0x45d9f3b;
    h = ((h >> 16) ^ h) & 255;
    mint cur = bases[h];
    std::uint32_t d = x - 1;
    int s = std::countr_zero(d);
    d >>= s;
    cur = cur.pow(d);
    if (cur.val() == 1) return true;
    while (--s) {
        if (cur.val() == x - 1) return true;
        cur *= cur;
    }
    return cur.val() == x - 1;
}
template<bool trial_division = true> bool isPrime64(const std::uint64_t x) {
    if (x < 4294967296) return isPrime32<trial_division>(x);
    if constexpr (trial_division) {
        if (x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0 || x % 11 == 0 || x % 13 == 0 || x % 17 == 0 || x % 19 == 0 || x % 23 == 0 || x % 29 == 0 || x % 31 == 0 || x % 37 == 0 || x % 41 == 0 || x % 43 == 0) return false;
    } else {
        if (x % 2 == 0) return false;
    }
    using mint = DynamicModint64<-1>;
    mint::set_mod(x);
    std::uint64_t d = x - 1;
    const int s = std::countr_zero(d);
    d >>= s;
    auto test = [&](std::uint64_t a) -> bool {
        mint cur = mint(a).pow(d);
        if (cur.val() <= 1) return true;
        int i = s;
        while (--i) {
            if (cur.val() == x - 1) return true;
            cur *= cur;
        }
        return cur.val() == x - 1;
    };
    return test(2) && test(325) && test(9375) && test(28178) && test(450775) && test(9780504) && test(1795265022);
}

int main() {
    int Q;
    fin >> Q;
    rep(Q) {
        ull N;
        fin >> N;
        fout << N << ' ' << isPrime64<false>(N) << '\n';
    }
}
0