結果
| 問題 | No.8030 ミラー・ラビン素数判定法のテスト |
| ユーザー |
iwkjosec
|
| 提出日時 | 2026-08-11 13:34:35 |
| 言語 | C# (.NET 10.0.201) |
| 結果 |
AC
|
| 実行時間 | 188 ms / 9,973 ms |
| + 237µs | |
| コード長 | 7,552 bytes |
| 記録 | |
| コンパイル時間 | 14,486 ms |
| コンパイル使用メモリ | 172,276 KB |
| 実行使用メモリ | 196,356 KB |
| 最終ジャッジ日時 | 2026-08-11 13:35:19 |
| 合計ジャッジ時間 | 14,168 ms |
|
ジャッジサーバーID (参考情報) |
judge2_0 / judge1_0 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 10 |
コンパイルメッセージ
復元対象のプロジェクトを決定しています... /home/judge/data/code/main.csproj を復元しました (82 ミリ秒)。 /home/judge/data/code/Main.cs(244,13): warning CA2022: 'System.IO.Stream.Read(byte[], int, int)' による不正確な読み取りを避ける (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2022) [/home/judge/data/code/main.csproj] main -> /home/judge/data/code/bin/Release/net10.0/main.dll main -> /home/judge/data/code/bin/Release/net10.0/publish/
ソースコード
using System.Diagnostics;
using System.Numerics;
class Program
{
static void Main()
{
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
var n = FastIO.Long();
for (int i = 0; i < n; i++)
{
var x = (ulong)FastIO.Long();
Console.WriteLine($"{x} {(MillerRabin(x) ? '1' : '0')}");
}
Console.Out.Flush();
}
public static ulong MontgomeryReduction
(ulong xlo, ulong xhi, ulong m, ulong mInv)
{
ulong result = xhi - Math.BigMul(xlo * mInv, m, out _);
return result > xhi ? result + m : result;
}
public static ulong BigMul(ulong a, ulong b, out ulong lo)
{
ulong alo = a & 0xffffffff, ahi = a >> 32;
ulong blo = b & 0xffffffff, bhi = b >> 32;
ulong lolo = alo * blo;
ulong lohi = alo * bhi;
ulong hilo = ahi * blo;
ulong hihi = ahi * bhi;
lo = lolo + ((lohi + hilo) << 32);
ulong carry = ((lolo >> 32) + (lohi & 0xffffffff) + (hilo & 0xffffffff)) >> 32;
ulong hi = hihi + (lohi >> 32) + (hilo >> 32) + carry;
return hi;
}
public static ulong MultiplicativeInverse(ulong a)
{
Debug.Assert((a & 1) != 0);
ulong x0 = (3 * a) ^ 2;
ulong y = 1 - a * x0;
ulong x1 = x0 * (1 + y);
y *= y;
ulong x2 = x1 * (1 + y);
y *= y;
ulong x3 = x2 * (1 + y);
y *= y;
ulong x4 = x3 * (1 + y);
return x4;
}
public static ulong MontgomeryMultiplication(ulong a, ulong b, ulong m, ulong mInv)
{
ulong xhi = Math.BigMul(a, b, out ulong xlo);
return MontgomeryReduction(xlo, xhi, m, mInv);
}
public static ulong MontgomeryAddition(ulong a, ulong b, ulong m)
{
ulong add = a + b;
return add < a || add >= m ? add - m : add;
}
public static ulong MontgomerySubtraction(ulong a, ulong b, ulong m)
{
ulong sub = a - b;
return a < b ? sub + m : sub;
}
public static (ulong modinv, ulong rmod, ulong r2mod)
MontgomeryConstant(ulong mod)
{
ulong modinv = MultiplicativeInverse(mod);
ulong rmod = (0ul - mod) % mod;
ulong r2mod = rmod;
r2mod = MontgomeryAddition(r2mod, r2mod, mod);
r2mod = MontgomeryAddition(r2mod, r2mod, mod);
r2mod = MontgomeryMultiplication(r2mod, r2mod, mod, modinv);
r2mod = MontgomeryMultiplication(r2mod, r2mod, mod, modinv);
r2mod = MontgomeryMultiplication(r2mod, r2mod, mod, modinv);
r2mod = MontgomeryMultiplication(r2mod, r2mod, mod, modinv);
r2mod = MontgomeryMultiplication(r2mod, r2mod, mod, modinv);
return (modinv, rmod, r2mod);
}
public static ulong ModPow(ulong value, ulong exponent, ulong mod)
{
var (modinv, rmod, r2mod) = MontgomeryConstant(mod);
ulong power = MontgomeryMultiplication(value, r2mod, mod, modinv);
ulong result = 1;
while (exponent > 0)
{
if ((exponent & 1) != 0)
{
result = MontgomeryMultiplication(result, power, mod, modinv);
}
power = MontgomeryMultiplication(power, power, mod, modinv);
exponent >>= 1;
}
return result;
}
private static readonly byte[] TrailingZeroLookup = [
0, 1, 59, 2, 60, 40, 54, 3, 61, 32, 49, 41, 55, 19, 35, 4, 62, 52, 30, 33, 50, 12, 14, 42, 56, 16, 27, 20, 36, 23, 44, 5, 63,
58, 39, 53, 31, 48, 18, 34, 51, 29, 11, 13, 15, 26, 22, 43, 57, 38, 47, 17, 28, 10, 25, 21, 37, 46, 9, 24, 45, 8, 7, 6
];
public static int TrailingZeroCount(ulong value)
{
if (value == 0)
{
return 64;
}
return TrailingZeroLookup[((value & (0 - value)) * 0x03F566ED27179461) >> 58];
}
public static ulong ModMul(ulong a, ulong b, ulong mod)
{
// if mod is even then
if ((mod & 1) == 0)
{
int evenBits = TrailingZeroCount(mod);
ulong oddMod = mod >> evenBits;
var (modinv, rmod, r2mod) = MontgomeryConstant(oddMod);
ulong mask = (1ul << evenBits) - 1;
// MR(a * b)
ulong thi = BigMul(a, b, out ulong tlo);
ulong tOdd = thi - BigMul(tlo * modinv, oddMod, out _);
if (tOdd > thi)
{
tOdd += oddMod;
}
// == (a * b) & mask
ulong tEven = tlo & mask;
// MR(ab * R^2)
thi = BigMul(tOdd, r2mod, out tlo);
tOdd = thi - BigMul(tlo * modinv, oddMod, out _);
if (tOdd > thi)
{
tOdd += oddMod;
}
// Garner's algorithm
ulong t = tOdd + (((tEven - tOdd) * modinv) & mask) * oddMod;
return t;
}
else
{
// if mod is odd then
// do normal Montgomery Multiplication
var (modinv, rmod, r2mod) = MontgomeryConstant(mod);
var mont = MontgomeryMultiplication(MontgomeryMultiplication(
a, b, mod, modinv), r2mod, mod, modinv);
return mont;
}
}
// returns true if value is prime
public static bool MillerRabin(ulong value)
{
// 2 以下・偶数の場合の前処理
if (value <= 2)
{
return value == 2;
}
if ((value & 1) == 0)
{
return false;
}
ulong n1 = value - 1;
int s = TrailingZeroCount(n1);
ulong d = n1 >> s;
// 「注意深く選ばれた」定数
// 2^64 までならこの 7 つで対応可能
ReadOnlySpan<ulong> MillerRabinConstants =
[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
foreach (var a in MillerRabinConstants)
{
// 割り切れた場合は続行
if (a % value == 0)
{
continue;
}
// a^d mod value == 1 or value-1 なら続行
ulong t = ModPow(a, d, value);
if (t == 1 || t == n1)
{
continue;
}
// t^(2^i) mod value について、
// == value-1 の要素があれば続行、なければ合成数
int i;
for (i = 0; i < s; i++)
{
t = ModMul(t, t, value);
if (t == n1)
{
break;
}
}
if (i == s)
{
return false;
}
}
// 全てのテストを通過したら素数
return true;
}
}
public static class FastIO
{
static Stream str = Console.OpenStandardInput();
const int size = 1024;
static byte[] buffer = new byte[size];
static int ptr = size;
static byte Read()
{
if (ptr == size)
{
str.Read(buffer, 0, size);
ptr = 0;
}
return buffer[ptr++];
}
public static long Long()
{
var c = Read();
while (c < 0x21)
{
c = Read();
}
var n = false;
if (c == '-')
{
n = true;
c = Read();
}
var ret = 0L;
while (c > 0x20)
{
ret = ret * 10 + c - '0';
c = Read();
}
return n ? -ret : ret;
}
}
iwkjosec