結果
問題 |
No.8030 ミラー・ラビン素数判定法のテスト
|
ユーザー |
|
提出日時 | 2025-05-19 08:58:28 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 56 ms / 9,973 ms |
コード長 | 4,921 bytes |
コンパイル時間 | 1,254 ms |
コンパイル使用メモリ | 102,784 KB |
実行使用メモリ | 6,272 KB |
最終ジャッジ日時 | 2025-05-19 08:58:31 |
合計ジャッジ時間 | 2,538 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 10 |
ソースコード
#include <algorithm> #include <bit> #include <cassert> #include <concepts> #include <iostream> #include <limits> #include <type_traits> #include <vector> #include <cstdint> namespace wasd314 { struct dynamic_modint1 { using U = uint64_t; using UU = __uint128_t; using I = std::make_signed_t<U>; using mint = dynamic_modint1; U rx; static inline U mod; static inline U R_1; static inline U R1; static inline U R2; static inline U N_; static constexpr int bits_u = std::numeric_limits<U>::digits; static constexpr int bits_half = bits_u / 2; static U get_N_() { U n_inv = mod; for (int bits = 2; bits < bits_u; bits <<= 1) { n_inv *= 2 - n_inv * mod; } return -n_inv; } static U get_R1() { return -mod % mod; } static U get_R2() { return -UU(mod) % mod; } static U get_R_1() { return (1 + UU(mod) * N_) >> bits_u; } static void set_mod(U new_mod) { assert(I(new_mod) > 0); assert(new_mod & 1); mod = new_mod; N_ = get_N_(); R1 = get_R1(); R2 = get_R2(); R_1 = get_R_1(); } static U safe_mod(I x) { x %= I(mod); if (x < 0) x += I(mod); return x; } static U reduce(const UU &x) { U y = (x + UU(U(x) * N_) * mod) >> bits_u; return y < mod ? y : y - mod; } dynamic_modint1(const I &x) : rx(reduce(UU(safe_mod(x)) * R2)) {} // for literal dynamic_modint1(I &&x) : rx(reduce(UU(safe_mod(x)) * R2)) {} private: dynamic_modint1(const U &x, auto) : rx(x) {} public: static mint raw(const U &x) { return mint(x, 0); } U val() const { return reduce(rx); } mint pow(uint64_t e) const { mint ans = raw(R1), b(*this); while (e) { if (e & 1) ans *= b; b *= b; e >>= 1; } return ans; } mint &operator+=(const mint &o) { rx += o.rx; if (rx >= mod) rx -= mod; return *this; } mint &operator-=(const mint &o) { if (__builtin_sub_overflow(rx, o.rx, &rx)) rx += mod; return *this; } mint &operator*=(const mint &o) { rx = reduce(UU(rx) * o.rx); return *this; } mint operator+() const { return mint(*this); } mint operator-() const { return mint::raw(0) -= *this; } }; using mint = dynamic_modint1; bool operator==(const mint &x, const mint &y) { return x.rx == y.rx; } bool operator!=(const mint &x, const mint &y) { return !(x == y); } mint operator+(const mint &x, const mint &y) { return mint(x) += y; } mint operator-(const mint &x, const mint &y) { return mint(x) -= y; } mint operator*(const mint &x, const mint &y) { return mint(x) *= y; } using lint = long long; using u64 = uint64_t; bool is_prime(u64 n) { // using lint2 = __int128_t; if (n < 2) return false; for (u64 p : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) { if (n == p) return true; if (n % p == 0) return false; } if (n < 41 * 41) return true; mint::set_mod(n); const mint one = mint::raw(mint::R1), neg_one = -one; auto test_miller_rabin = [&](const std::vector<lint> &bases) { int e = std::countr_zero(n - 1); u64 o = n >> e; for (lint b : bases) { mint x = mint(b).pow(o); if (x == one) continue; for (int ei = 0; ei < e; ++ei) { mint y = x * x; if (y == one) { if (x == neg_one) break; return false; } x = y; if (ei == e - 1) return false; } } return true; }; if (n < 2047) return test_miller_rabin({2}); if (n < 9080191) return test_miller_rabin({31, 73}); if (n < 4759123141) return test_miller_rabin({2, 7, 61}); if (n < 1122004669633) return test_miller_rabin({2, 13, 23, 1662803}); if (n < 3770579582154547) return test_miller_rabin({2, 880937, 2570940, 610386380, 4130785767}); return test_miller_rabin({2, 325, 9375, 28178, 450775, 9780504, 1795265022}); } } // namespace wasd314 int main() { using namespace std; using namespace wasd314; int q; cin >> q; for (int _ = 0; _ < q; ++_) { lint n; cin >> n; cout << n << ' ' << is_prime(n) << "\n"; } }