結果

問題 No.3030 ミラー・ラビン素数判定法のテスト
ユーザー iwkjoseciwkjosec
提出日時 2019-05-18 01:02:02
言語 C#(csc)
(csc 3.9.0)
結果
WA  
実行時間 -
コード長 9,570 bytes
コンパイル時間 3,145 ms
コンパイル使用メモリ 109,824 KB
実行使用メモリ 23,552 KB
最終ジャッジ日時 2024-04-29 13:13:15
合計ジャッジ時間 14,643 ms
ジャッジサーバーID
(参考情報)
judge5 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 WA -
testcase_01 AC 25 ms
17,792 KB
testcase_02 AC 27 ms
17,664 KB
testcase_03 AC 28 ms
17,664 KB
testcase_04 TLE -
testcase_05 -- -
testcase_06 -- -
testcase_07 -- -
testcase_08 -- -
testcase_09 -- -
権限があれば一括ダウンロードができます
コンパイルメッセージ
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 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;
                x = x * x % nn;
            }
            if (c) return false;
        }
        return true;
    }


}

struct UInt128
{
    public ulong low;
    public ulong high;

    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)
    {
        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 l, UInt128 r)//rが奇数になるまでlr両方に右シフトしてよい//アルゴが思いつかないから繰り返し2倍法
    {
        if (r == 0) throw new DivideByZeroException();

        while ((r.low & 1) == 0)
        {
            r >>= 1;
            l >>= 1;
        }

        var m = (UInt128)1;
        var q = (UInt128)0;
        while (r <= l)
        {
            r <<= 1;
            m <<= 1;
        }
        while (1 < m)
        {
            r >>= 1;
            m >>= 1;
            if (l >= r)
            {
                l -= r;
                q |= m;
            }
        }

        return q;
    }

    public static UInt128 operator %(UInt128 l, UInt128 r)//DivRem作った方がいいのか
    {
        return l - l / r * r;
    }

    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;
            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;
            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)
    {
        return l.high > r.high || l.low > r.low;
    }

    public static bool operator <(UInt128 l, UInt128 r)
    {
        return l.high < r.high || 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 = 0;
        for (int i = 0; i < s.Length; i++)
        {
            if (s[i] != '0')
            {
                a = i;
                break;
            }
        }
        s = s.Substring(a == s.Length - 1 ? a - 1 : 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 += (uint)(s[i] - '0');
        }
        return ret;
    }

    public override string ToString()
    {
        if (this == 0) return "0";
        var a = this;
        var ret = new List<char>(40);
        while (a != 0)
        {
            ret.Add((char)((int)(a % 10) + '0'));
            a /= 10;
        }
        ret.Reverse();
        return new string(ret.ToArray());
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }
}
0