結果
問題 | No.3030 ミラー・ラビン素数判定法のテスト |
ユーザー | nonamae |
提出日時 | 2022-07-25 08:36:47 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
RE
|
実行時間 | - |
コード長 | 5,056 bytes |
コンパイル時間 | 1,733 ms |
コンパイル使用メモリ | 205,128 KB |
実行使用メモリ | 6,944 KB |
最終ジャッジ日時 | 2024-07-07 05:26:49 |
合計ジャッジ時間 | 3,424 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,812 KB |
testcase_01 | AC | 2 ms
6,944 KB |
testcase_02 | AC | 1 ms
6,944 KB |
testcase_03 | AC | 1 ms
6,944 KB |
testcase_04 | RE | - |
testcase_05 | RE | - |
testcase_06 | RE | - |
testcase_07 | RE | - |
testcase_08 | RE | - |
testcase_09 | RE | - |
ソースコード
#include <bits/stdc++.h> using i8 = std::int8_t; using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using i128 = __int128_t; using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using u128 = __uint128_t; template<typename T> using vec = std::vector<T>; template<typename T> using vvec = std::vector<std::vector<T>>; template<typename T> using vvvec = std::vector<std::vector<std::vector<T>>>; int jacobi(i64 a, u64 n) { u64 t; int j = 1; while (a) { if (a < 0) { a = -a; if ((n & 3) == 3) j = -j; } int s = __builtin_ctzll(a); a >>= s; if (((n & 7) == 3 || (n & 7) == 5) && (s & 1)) j = -j; if ((a & n & 3) == 3) j = -j; t = a, a = n, n = t; a %= n; if (((u64)a) > (n / 2)) a -= n; } return n == 1 ? j : 0; } struct m64 { // r * m === -1 (mod 1<<64), n2 === 1<<<128 (mod m) inline static u64 m, r, n2; static void set_mod(u64 m) { assert(m < (1ull << 62)); assert((m & 1) == 1); m64::m = m; n2 = -u128(m) % m; r = m; for (int _ = 0; _ < 5; ++_) r *= 2 - m * r; r = -r; assert(r * m == -1ull); } static u64 reduce(u128 b) { return (b + u128(u64(b) * r) * m) >> 64; } u64 x; m64() : x(0) {} m64(u64 x) : x(reduce(u128(x) * n2)) {} u64 val() const { u64 y = reduce(x); return y >= m ? y - m : y; } m64 &operator+=(m64 y) { x += y.x - (m << 1); x = (i64(x) < 0 ? x + (m << 1) : x); return *this; } m64 &operator-=(m64 y) { x -= y.x; x = (i64(x) < 0 ? x + (m << 1) : x); return *this; } m64 &operator*=(m64 y) { x = reduce(u128(x) * y.x); return *this; } m64 &operator/=(m64 y) { *this *= y.inv(); return *this; } m64 &operator<<=(int y) { m64 a(1ull << y); *this *= a; return *this; } m64 &operator>>=(int y) { m64 a(1ull << y); *this /= a; return *this; } m64 operator+(m64 y) const { return m64(*this) += y; } m64 operator-(m64 y) const { return m64(*this) -= y; } m64 operator*(m64 y) const { return m64(*this) *= y; } m64 operator/(m64 y) const { return m64(*this) /= y; } m64 operator<<(int y) const { return m64(*this) <<= y; } m64 operator>>(int y) const { return m64(*this) >>= y; } bool operator==(m64 y) const { return (x >= m ? x-m : x) == (y.x >= m ? y.x-m : y.x); } bool operator!=(m64 y) const { return not operator==(y); } m64 pow(u64 n) const { m64 y = 1, z = *this; for ( ; n; n >>= 1, z *= z) if (n & 1) y *= z; return y; } m64 inv() const { return this->pow(m - 2); } }; bool is_prime(u64 n) { {// [1] /** 試し割り法 前処理として偶数と小さな数を判定しておく **/ if (n == 2 || n == 3 || n == 5 || n == 7) return true; if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n % 7 == 0) return false; if (n < 121) return n > 1; } m64::set_mod(n); {// [2] /** 2を底とするMiller-Rabinテストにより、強フェルマー擬素数を見つける **/ u64 d = (n - 1) << __builtin_clzll(n - 1); m64 t(2); for (d <<= 1; d; d <<= 1) { t *= t; if (d >> 63) t <<= 1; } if (t != m64(1)) { u64 x = (n - 1) & -(n - 1); m64 rev(n - 1); for (x >>= 1; t != rev; x >>= 1) { if (x == 0) return false; t *= t; } } } {// [3] /** 初期値・係数の決定 **/ i64 D = 5; for (int i = 0; jacobi(D, n) != -1 && i < 64; ++i) { if (i == 32) { u32 k = round(sqrtl(n)); if (k * k == n) return false; } if (i & 1) D -= 2; else D += 2; D = -D; } m64 Q(D < 0 ? (1 - D) / 4 % n : n - (D - 1) / 4 % n); m64 u(1), v(1), Qn(D < 0 ? (1 - D) / 4 % n : n - (D - 1) / 4 % n); m64 D_(D < 0 ? (n + D) % n : D % n ); u64 k = (n + 1) << __builtin_clzll(n + 1); for (k <<= 1; k; k <<= 1) { u *= v; v = v * v - Qn - Qn; Qn *= Qn; if (k >> 63) { m64 uu = (u + v) >> 1; v += D_ * u; v >>= 1; u = uu; Qn *= Q; } } if (u == m64(0) || v == m64(0)) return true; u64 x = (n + 1) & ~n; for (x >>= 1; x; x >>= 1) { u *= v; v = v * v - Qn - Qn; if (v == m64(0)) return true; Qn *= Qn; } } return false; } int main(void) { int n; scanf("%d", &n); while (n--) { u64 x; scanf("%lu", &x); printf("%lu %d\n", x, is_prime(x)); } }