結果
| 問題 |
No.8030 ミラー・ラビン素数判定法のテスト
|
| ユーザー |
iwkjosec
|
| 提出日時 | 2020-09-13 06:34:46 |
| 言語 | C#(csc) (csc 3.9.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 14,374 bytes |
| コンパイル時間 | 1,143 ms |
| コンパイル使用メモリ | 119,960 KB |
| 実行使用メモリ | 29,268 KB |
| 最終ジャッジ日時 | 2024-11-18 18:26:22 |
| 合計ジャッジ時間 | 34,157 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 8 WA * 1 TLE * 1 |
コンパイルメッセージ
Microsoft (R) Visual C# Compiler version 3.9.0-6.21124.20 (db94f4cc) Copyright (C) Microsoft Corporation. All rights reserved.
ソースコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static System.Console;
using static System.Math;
using System.Numerics;
class Program
{
static void Main()
{
var n = long.Parse(ReadLine());
for (int i = 0; i < n; i++)
{
var x = long.Parse(ReadLine());
WriteLine(x.ToString() + " " + (MillerRabin(x) ? "1" : "0"));
}
}
static uint[] l = new uint[] { 2, 325, 9375, 28178, 450775, 9780504, 1795265022 };
static bool MillerRabin(long n)
{
if (n < 2) return false;
if (n % 2 == 0) return n == 2;
var d = n - 1;
var s = 0;
while (d % 2 == 0)
{
s++;
d >>= 1;
}
var dd = (UInt128)d;
var nn = (UInt128)n;
for (int i = 0; i < l.Length && l[i] < n; i++)
{
var a = l[i];
var c = true;
var x = UInt128.ModPow(a, dd, nn);
if (x == 1) c = false;
for (int r = 0; r < s; r++)
{
if (x == nn - 1) c = false;
if (!c) break;
x = x * x % nn;
}
if (c) return false;
}
return true;
}
}
public struct UInt128
{
public ulong low;
public ulong high;
public static UInt128 MaxValue => new UInt128 { low = ulong.MaxValue, high = ulong.MaxValue };
public static UInt128 MinValue => 0;
public UInt128(ulong h, ulong l)
{
low = l;
high = h;
}
public static UInt128 operator +(UInt128 l, UInt128 r)//片方にもう片方足して返すのとin引数にして新しいインスタンス返すのどっちがいいんだろう
{
var s = new UInt128 { low = l.low + r.low, high = l.high + r.high };
if (s.low < l.low) s.high++;
return s;
}
public static UInt128 operator -(UInt128 l, UInt128 r)//l + ~r + 1 だと思うけどこれでも正しそう
{
var s = new UInt128 { low = l.low - r.low, high = l.high - r.high };
if (s.low > l.low) s.high--;
return s;
}
public static UInt128 operator *(UInt128 l, UInt128 r)//導出は n bit * n bit -> 2n bit ができないとき 上位ビット下位ビットに分割して考える
{
var h = l.low * r.high + l.high * r.low;
var lll = l.low & 0xFFFFFFFF;
var llh = l.low >> 32;
var rll = r.low & 0xFFFFFFFF;
var rlh = r.low >> 32;
var a = lll * rll;
var b = lll * rlh + llh * rll;
var c = llh * rlh;
if (b < lll * rlh) c += 1UL << 32;
var lo = a + (b << 32);
var hi = c + (b >> 32);
if (lo < a) hi++;
hi += h;
return new UInt128 { low = lo, high = hi };
}
public static UInt128 operator /(UInt128 left, UInt128 right)
{
if (left < right) return 0;
//var n = Min(TZC(left), TZC(right));
//left >>= n;
//right >>= n;
//var m = LZC(right) - LZC(left);
var m = LZC(right);
right <<= m;
var q = (UInt128)0;
while (m >= 0)
{
if (left >= right)
{
q |= (UInt128)1 << m;
left -= right;
}
right >>= 1;
m--;
}
return q;
}
// public static int TZC(UInt128 v)
//{
// if (v.low == 0) return BitOperations.TrailingZeroCount(v.high) + 64;
// else return BitOperations.TrailingZeroCount(v.low);
// }
public static int LZC(UInt128 v)
{
if (v.high == 0) return LeadingZeroCount(v.low) + 64;
else return LeadingZeroCount(v.high);
}
public static int LeadingZeroCount(uint value)
{
// Unguarded fallback contract is 0->31, BSR contract is 0->undefined
if (value == 0)
{
return 32;
}
return 31 ^ Log2SoftwareFallback(value);
}
public static int LeadingZeroCount(ulong value)
{
uint hi = (uint)(value >> 32);
if (hi == 0)
{
return 32 + LeadingZeroCount((uint)value);
}
return LeadingZeroCount(hi);
}
private static int Log2SoftwareFallback(uint value)
{
// No AggressiveInlining due to large method size
// Has conventional contract 0->0 (Log(0) is undefined)
// Fill trailing zeros with ones, eg 00010010 becomes 00011111
value |= value >> 01;
value |= value >> 02;
value |= value >> 04;
value |= value >> 08;
value |= value >> 16;
// uint.MaxValue >> 27 is always in range [0 - 31] so we use Unsafe.AddByteOffset to avoid bounds check
return Log2DeBruijn[(int)((value * 0x07C4ACDDu) >> 27)];
}
private static ReadOnlySpan<byte> Log2DeBruijn => new byte[32]
{
00, 09, 01, 10, 13, 21, 02, 29,
11, 14, 16, 18, 22, 25, 03, 30,
08, 12, 20, 28, 15, 17, 24, 07,
19, 27, 23, 06, 26, 05, 04, 31
};
public static UInt128 operator %(UInt128 left, UInt128 right)
{
return left - (left / right) * right;
}
public static UInt128 operator &(UInt128 l, UInt128 r)
{
return new UInt128 { low = l.low & r.low, high = l.high & r.high };
}
public static UInt128 operator |(UInt128 l, UInt128 r)
{
return new UInt128 { low = l.low | r.low, high = l.high | r.high };
}
public static UInt128 operator ^(UInt128 l, UInt128 r)
{
return new UInt128 { low = l.low ^ r.low, high = l.high ^ r.high };
}
public static UInt128 operator <<(UInt128 l, int r)
{
r &= 0x7F;
if (r >= 64)
{
l.high = l.low << r - 64;
l.low = 0;
}
else
{
l.high <<= r;
if (r != 0) l.high |= l.low >> 64 - r;
l.low <<= r;
}
return l;
}
public static UInt128 operator >>(UInt128 l, int r)
{
r &= 0x7F;
if (r >= 64)
{
l.low = l.high >> r - 64;
l.high = 0;
}
else
{
l.low >>= r;
if (r != 0) l.low |= l.high << 64 - r;
l.high >>= r;
}
return l;
}
public static bool operator ==(UInt128 l, UInt128 r)
{
return l.low == r.low && l.high == r.high;
}
public static bool operator !=(UInt128 l, UInt128 r)
{
return l.low != r.low || l.high != r.high;
}
public static bool operator >(UInt128 l, UInt128 r)
{
if (l.high > r.high) return true;
if (l.high < r.high) return false;
return l.low > r.low;
}
public static bool operator <(UInt128 l, UInt128 r)
{
if (l.high < r.high) return true;
if (l.high > r.high) return false;
return l.low < r.low;
}
public static bool operator >=(UInt128 l, UInt128 r)
{
if (l.high > r.high) return true;
if (l.high == r.high && l.low >= r.low) return true;
return false;
}
public static bool operator <=(UInt128 l, UInt128 r)
{
if (l.high < r.high) return true;
if (l.high == r.high && l.low <= r.low) return true;
return false;
}
public static UInt128 operator ~(UInt128 v)
{
v.low = ~v.low;
v.high = ~v.high;
return v;
}
public static UInt128 operator +(UInt128 v)
{
return v;
}
public static UInt128 operator ++(UInt128 v)
{
return v + 1;
}
public static UInt128 operator --(UInt128 v)
{
return v - 1;
}
public static explicit operator UInt128(sbyte v)
{
return new UInt128 { low = (ulong)v };
}
public static implicit operator UInt128(byte v)
{
return new UInt128 { low = v };
}
public static explicit operator UInt128(short v)
{
return new UInt128 { low = (ulong)v };
}
public static implicit operator UInt128(ushort v)
{
return new UInt128 { low = v };
}
public static explicit operator UInt128(int v)
{
return new UInt128 { low = (ulong)v };
}
public static implicit operator UInt128(uint v)
{
return new UInt128 { low = v };
}
public static explicit operator UInt128(long v)
{
return new UInt128 { low = (ulong)v };
}
public static implicit operator UInt128(ulong v)
{
return new UInt128 { low = v };
}
public static explicit operator UInt128(BigInteger v)
{
var ret = new UInt128 { low = (ulong)v };
v >>= 64;
ret.high = (ulong)v;
return ret;
}
public static explicit operator sbyte(UInt128 v)
{
return (sbyte)(v.low & 0x7F);
}
public static explicit operator byte(UInt128 v)
{
return (byte)v.low;
}
public static explicit operator short(UInt128 v)
{
return (short)(v.low & 0x7FFF);
}
public static explicit operator ushort(UInt128 v)
{
return (ushort)v.low;
}
public static explicit operator int(UInt128 v)
{
return (int)v.low & int.MaxValue;
}
public static explicit operator uint(UInt128 v)
{
return (uint)v.low;
}
public static explicit operator long(UInt128 v)
{
return (long)v.low & long.MaxValue;
}
public static explicit operator ulong(UInt128 v)
{
return v.low;
}
public static implicit operator BigInteger(UInt128 v)
{
return (new BigInteger(v.high) << 64) | v.low;
}
public static UInt128 ModPow(UInt128 x, UInt128 n, UInt128 m)
{
var res = (UInt128)1;
while (n != 0)
{
if ((n & 1) == 1) res = res * x % m;
x = x * x % m;
n >>= 1;
}
return res;
}
public static UInt128 Parse(string s)// -0を許容して -nはovfとして扱いたい 要はuint,ulongと挙動をそろえたい
{//スパゲッティフロー笑
if (s is null) throw new ArgumentNullException();
s = s.Trim();
if (s.Length == 0) throw new FormatException();
if (s[0] == '+')
{
if (s.Length == 1) throw new FormatException();
else s = s.Substring(1);
}
var a = -1;
for (int i = 0; i < s.Length; i++)
{
if (s[i] != '0')
{
a = i;
break;
}
}
if (a == -1) return new UInt128 { low = 0, high = 0 };
s = s.Substring(a);
if (s.Length > 39) throw new FormatException();
for (int i = 0; i < s.Length; i++)
{
if ((uint)(s[i] - '0') > '9') throw new FormatException();
}
if (s.Length == 39 && s.CompareTo("340282366920938463463374607431768211456") != -1) throw new OverflowException();
var ret = new UInt128();
for (int i = 0; i < s.Length; i++)
{
ret *= 10;
ret += (UInt128)(s[i] - '0');
}
return ret;
}
//適当 本当にこれでいいのかわからん
public static bool TryParse(string s, out UInt128 result)
{
try
{
result = Parse(s);
}
catch (Exception)
{
result = 0;
return false;
}
return true;
}
public static UInt128 FastParse(string s)
{
var ret = new UInt128();
for (int i = 0; i < s.Length; i++)
{
ret *= 10;
ret += (UInt128)(s[i] - '0');
}
return ret;
}
public override string ToString() // https://source.dot.net/#System.Private.CoreLib/shared/System/Number.Formatting.cs UInt32ToDecStr
{
if (this == 0) return "0";
var a = this;
var ret = new char[a.CountDisits()];
for (int i = ret.Length - 1; i >= 0; i--)
{
var d = a / 10;
ret[i] = (char)(a - (d * 10) + '0');
a = d;
}
return new string(ret);
}
static UInt128 e30;
static UInt128()
{
e30 = FastParse("1000000000000000000000000000000");
}
public int CountDisits()//if elseの所分割したら速い?プリミティブ型と違って除算が激遅だから展開した方が速い?
{
int digits = 1;
ulong part;
if (this >= 10000000000000000000UL)
{
if (this >= e30)
{
part = (ulong)(this / e30);
digits += 30;
}
else
{
part = (ulong)(this / 10000000000000000000UL);
digits += 19;
}
}
else
{
if (this >= 10000000000UL)
{
part = (ulong)(this / 10000000000UL);
digits += 10;
}
else
{
part = (ulong)this;
}
}
if (part < 10)
{
// no-op
}
else if (part < 100)
{
digits++;
}
else if (part < 1000)
{
digits += 2;
}
else if (part < 10000)
{
digits += 3;
}
else if (part < 100000)
{
digits += 4;
}
else if (part < 1000000)
{
digits += 5;
}
else if (part < 10000000)
{
digits += 6;
}
else if (part < 100000000)
{
digits += 7;
}
else if (part < 1000000000)
{
digits += 8;
}
else if (part < 10000000000)
{
digits += 9;
}
else
{
digits += 10;
}
return digits;
}
//Obsolate
public override bool Equals(object obj)
{
return base.Equals(obj);
}
//Obsolate //Dictionaryが参照する・・・?
public override int GetHashCode()
{
return base.GetHashCode();
}
}
iwkjosec