結果
| 問題 |
No.8030 ミラー・ラビン素数判定法のテスト
|
| ユーザー |
|
| 提出日時 | 2020-12-28 00:13:34 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 18 ms / 9,973 ms |
| コード長 | 5,988 bytes |
| コンパイル時間 | 2,252 ms |
| コンパイル使用メモリ | 203,008 KB |
| 最終ジャッジ日時 | 2025-01-17 07:47:50 |
|
ジャッジサーバーID (参考情報) |
judge4 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| 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;
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;
}
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 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;
}
namespace fastio {
static constexpr int SZ = 1 << 17;
char ibuf[SZ], obuf[SZ];
int pil = 0, pir = 0, por = 0;
struct Pre {
char num[40000];
constexpr Pre() : num() {
for (int i = 0; i < 10000; i++) {
int n = i;
for (int j = 3; j >= 0; j--) {
num[i * 4 + j] = n % 10 + '0';
n /= 10;
}
}
}
} constexpr pre;
inline void load() {
memcpy(ibuf, ibuf + pil, pir - pil);
pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
pil = 0;
}
inline void flush() {
fwrite(obuf, 1, por, stdout);
por = 0;
}
inline void rd(char& c) { c = ibuf[pil++]; }
template <typename T>
inline void rd(T& x) {
if (pil + 32 > pir) load();
char c;
do {
c = ibuf[pil++];
} while (c < '-');
bool minus = 0;
if (c == '-') {
minus = 1;
c = ibuf[pil++];
}
x = 0;
while (c >= '0') {
x = x * 10 + (c & 15);
c = ibuf[pil++];
}
if (minus) x = -x;
}
inline void wt(char c) { obuf[por++] = c; }
template <typename T>
inline void wt(T x) {
if (por > SZ - 32) flush();
if (!x) {
obuf[por++] = '0';
return;
}
if (x < 0) {
obuf[por++] = '-';
x = -x;
}
int i = 12;
char buf[16];
while (x >= 10000) {
memcpy(buf + i, pre.num + (x % 10000) * 4, 4);
x /= 10000;
i -= 4;
}
int d = x < 100 ? (x < 10 ? 1 : 2) : (x < 1000 ? 3 : 4);
memcpy(obuf + por, pre.num + x * 4 + 4 - d, d);
por += d;
memcpy(obuf + por, buf + i + 4, 12 - i);
por += 12 - i;
}
struct Dummy {
Dummy() { atexit(flush); }
} dummy;
} // namespace fastio
using fastio::rd;
using fastio::wt;
using namespace std;
int main() {
cin.tie(nullptr);
cout.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(15);
int query; rd(query);
while (query--) {
Word64 x; rd(x);
int ans = solovay_strassen(x);
wt(x); wt(' '); wt(ans); wt('\n');
}
return 0;
}