結果
| 問題 | No.8030 ミラー・ラビン素数判定法のテスト |
| ユーザー |
|
| 提出日時 | 2020-12-27 23:59:12 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.89.0) |
| 結果 |
AC
|
| 実行時間 | 17 ms / 9,973 ms |
| コード長 | 4,219 bytes |
| 記録 | |
| コンパイル時間 | 1,800 ms |
| コンパイル使用メモリ | 196,084 KB |
| 最終ジャッジ日時 | 2025-01-17 07:47:35 |
|
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 10 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using Int8 = int8_t;
using Int16 = int16_t;
using Int32 = int32_t;
using Int64 = int64_t;
using Int128 = __int128_t;
using Word8 = uint8_t;
using Word16 = uint16_t;
using Word32 = uint32_t;
using Word64 = uint64_t;
using Word128 = __uint128_t;
using Int = int_fast64_t;
using Word = uint_fast64_t;
using F32 = float;
using F64 = double;
using F80 = long double;
int jacobi(Int a, Word n) {
Word t;
int j = 1;
while(a) {
if (a < 0) {
a = -a ;
if ((n & 3) == 3) j = -j;
}
int ba = __builtin_ctzll(a);
a >>= ba;
if (((n & 7) == 3 || (n & 7) == 5) && (ba & 1)) j = -j;
if ((a & n & 3) == 3) j = -j;
t = a;
a = n;
n = t;
a %= n;
if (a > n / 2) a -= n;
}
return n == 1 ? j : 0;
}
static inline Word addmod64(Word x, Word y, Word n) { return x + y >= n ? x + y - n : x + y; }
static inline Word submod64(Word x, Word y, Word n) { return x >= y ? x - y : x - y + n; }
static inline Word ex_gcd(Word y) {
Word u = 1, v = 0;
Word x = 1ULL << 63;
for (int i = 0; i < 64; i++) {
if (u & 1){
u = (u + y) / 2;
v = v / 2 + x;
}
else {
u >>= 1;
v >>= 1;
}
}
return -v;
}
static inline Word64 MR(Word128 x, Word64 m, Word64 n) {
Int64 z = (x >> 64) - ((((Word64)x * m) * (Word128)n) >> 64);
return z < 0 ? z + n : z;
}
static inline Word64 RM(Word64 x, Word64 r2, Word64 m, Word64 n) { return MR((Word128)r2 * x, m, n); }
static inline Word64 mulmod64(Word64 x, Word64 y, Word64 m, Word64 n) { return MR((Word128)x * y, m, n); }
int solovay_strassen(const Word64 n) {
if(n <= 1) return 0;
if(n <= 3) return 1;
if(!(n & 1)) return 0;
const Word64 one = -1ULL % n + 1;
const Word64 r2 = (Word128) (Int128) -1 % n + 1;
const Word64 m = ex_gcd(n);
{
Word64 d = (n - 1) << __builtin_clzll(n-1);
Word64 t = one << 1;
if (t >= n) t -= n;
for (d <<= 1; d; d <<= 1) {
t = mulmod64(t, t, m, n);
if (d >> 63) {
t <<= 1;
if (t >= n) t -= n;
}
}
if(t != one){
Word64 x = (n - 1) & -(n - 1);
Word64 mone = n - one;
for (x >>= 2; t != mone; x >>= 1) {
if (x == 0) return 0;
t = mulmod64(t, t, m, n);
}
}
}
{
Int64 D = 5;
for(int i = 0; jacobi(D, n) != -1 && i < 64; i++) {
if(i == 32){
Word32 k = round(sqrtl(n));
if (k * k == n) return 0;
}
if (i & 1) D -= 2;
else D += 2;
D = -D;
}
Word64 Q = RM(D < 0 ? (1 - D) / 4 % n : n - (D - 1) / 4 % n, r2, m, n);
Word64 u, v, Qn;
Word64 k = (n + 1) << __builtin_clzll(n + 1);
u = one;
v = one;
Qn = Q;
D %= (Int64)n;
D = RM(D < 0 ? n + D : D, r2, m, n);
for (k <<= 1; k; k <<= 1) {
u = mulmod64(u,v,m,n);
v = submod64(mulmod64(v,v,m,n), addmod64(Qn, Qn, n), n);
Qn = mulmod64(Qn, Qn, m, n);
if (k >> 63) {
Word64 uu = addmod64(u, v, n);
if (uu & 1) uu += n;
uu >>= 1;
v = addmod64(mulmod64(D,u,m,n), v, n);
if (v & 1) v += n;
v >>= 1;
u = uu;
Qn = mulmod64(Qn, Q, m, n);
}
}
if (u == 0 || v == 0) return 1;
Word64 x = (n + 1) & ~n;
for (x >>= 2; x; x >>= 1) {
u = mulmod64(u,v,m,n);
v = submod64(mulmod64(v,v,m,n), addmod64(Qn, Qn, n), n);
if (v == 0) return 1;
Qn = mulmod64(Qn, Qn, m, n);
}
}
return 0;
}
int main() {
cin.tie(nullptr);
cout.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(15);
int query; cin >> query;
while (query--) {
Word64 x; cin >> x;
cout << x << ' ' << solovay_strassen(x) << '\n';
}
return 0;
}