結果

問題 No.3030 ミラー・ラビン素数判定法のテスト
ユーザー iwkjoseciwkjosec
提出日時 2020-09-13 06:34:46
言語 C#(csc)
(csc 3.9.0)
結果
WA  
実行時間 -
コード長 14,374 bytes
コンパイル時間 1,077 ms
コンパイル使用メモリ 110,720 KB
実行使用メモリ 23,296 KB
最終ジャッジ日時 2024-04-29 14:19:07
合計ジャッジ時間 34,852 ms
ジャッジサーバーID
(参考情報)
judge2 / judge4
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 AC 25 ms
17,664 KB
testcase_02 AC 25 ms
17,536 KB
testcase_03 AC 28 ms
17,408 KB
testcase_04 AC 7,192 ms
19,456 KB
testcase_05 AC 6,904 ms
19,200 KB
testcase_06 AC 2,662 ms
19,584 KB
testcase_07 AC 2,628 ms
19,328 KB
testcase_08 AC 2,622 ms
19,456 KB
testcase_09 TLE -
権限があれば一括ダウンロードができます
コンパイルメッセージ
Microsoft (R) Visual C# Compiler version 3.9.0-6.21124.20 (db94f4cc)
Copyright (C) Microsoft Corporation. All rights reserved.

ソースコード

diff #

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();
    }
}
0