题解:BISHI39 【模板】Pollard-Pho算法

题目链接

【模板】Pollard-Pho算法(素数判定)

题目描述

给定 组询问,每次给出一个正整数 ,判断 是否为质数。 可能较大。

解题思路

本题仅需素性测试,用 Miller–Rabin(米勒拉宾)随机化判定的确定化基即可在 位范围内常数时间判素:

  • 写成 ,任选若干底数 ,计算 ;若 则当前底数通过;否则反复平方 次,若出现 则通过,否则判合数。
  • 对于 ,底数集合 已足以确定化。

如需进一步做分解,可在此基础上加入 Pollard–Rho,但本题不需要分解,仅判素即可。

代码

#include <bits/stdc++.h>
using namespace std;

using u128 = __uint128_t;
using u64 = unsigned long long;
using u32 = unsigned int;

u64 mul_mod(u64 a, u64 b, u64 mod) {
    return (u128)a * b % mod;
}

u64 pow_mod(u64 a, u64 d, u64 mod) {
    u64 r = 1;
    while (d) {
        if (d & 1) r = mul_mod(r, a, mod);
        a = mul_mod(a, a, mod);
        d >>= 1;
    }
    return r;
}

bool miller_rabin(u64 n) {
    if (n < 2) return false;
    for (u64 p : {2ull,3ull,5ull,7ull,11ull,13ull,17ull}) {
        if (n % p == 0) return n == p;
    }
    u64 d = n - 1, s = 0;
    while ((d & 1) == 0) { d >>= 1; ++s; }
    auto trial = [&](u64 a) -> bool {
        u64 x = pow_mod(a % n, d, n);
        if (x == 1 || x == n - 1) return true;
        for (u64 r = 1; r < s; ++r) {
            x = mul_mod(x, x, n);
            if (x == n - 1) return true;
        }
        return false;
    };
    for (u64 a : {2ull,3ull,5ull,7ull,11ull,13ull,17ull}) {
        if (!trial(a)) return false;
    }
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T; 
    if (!(cin >> T)) return 0;
    while (T--) {
        unsigned long long n; 
        cin >> n;
        cout << (miller_rabin(n) ? "Yes" : "No") << '\n';
    }
    return 0;
}
import java.io.*;
import java.math.BigInteger;

public class Main {
    static class FastScanner {
        private final InputStream in;
        private final byte[] buffer = new byte[1 << 16];
        private int ptr = 0, len = 0;
        FastScanner(InputStream is) { this.in = is; }
        private int read() throws IOException {
            if (ptr >= len) {
                len = in.read(buffer);
                ptr = 0;
                if (len <= 0) return -1;
            }
            return buffer[ptr++];
        }
        String next() throws IOException {
            StringBuilder sb = new StringBuilder();
            int c;
            do { c = read(); } while (c <= 32);
            while (c > 32) { sb.append((char)c); c = read(); }
            return sb.toString();
        }
        int nextInt() throws IOException { return Integer.parseInt(next()); }
    }

    static final long[] BASES = {2,3,5,7,11,13,17,19,23,29,31,37};

    static boolean isPrime(BigInteger n) {
        if (n.compareTo(BigInteger.valueOf(2)) < 0) return false;
        if (n.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) return n.equals(BigInteger.valueOf(2));
        BigInteger d = n.subtract(BigInteger.ONE);
        int s = 0;
        while (d.and(BigInteger.ONE).equals(BigInteger.ZERO)) { d = d.shiftRight(1); s++; }
        for (long aLong : BASES) {
            if (BigInteger.valueOf(aLong).compareTo(n.subtract(BigInteger.ONE)) >= 0) continue;
            BigInteger a = BigInteger.valueOf(aLong);
            BigInteger x = a.modPow(d, n);
            if (x.equals(BigInteger.ONE) || x.equals(n.subtract(BigInteger.ONE))) continue;
            boolean pass = false;
            for (int r = 1; r < s; r++) {
                x = x.multiply(x).mod(n);
                if (x.equals(n.subtract(BigInteger.ONE))) { pass = true; break; }
            }
            if (!pass) return false;
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        FastScanner fs = new FastScanner(System.in);
        StringBuilder out = new StringBuilder();
        int T = fs.nextInt();
        while (T-- > 0) {
            BigInteger n = new BigInteger(fs.next());
            out.append(isPrime(n) ? "Yes" : "No").append('\n');
        }
        System.out.print(out.toString());
    }
}
import sys

def is_probable_prime(n: int) -> bool:
    if n < 2:
        return False
    small_primes = [2, 3, 5, 7, 11, 13, 17]
    for p in small_primes:
        if n % p == 0:
            return n == p
    # write n-1 = d * 2^s
    d = n - 1
    s = 0
    while d % 2 == 0:
        d //= 2
        s += 1
    def trial(a: int) -> bool:
        x = pow(a % n, d, n)
        if x == 1 or x == n - 1:
            return True
        for _ in range(s - 1):
            x = (x * x) % n
            if x == n - 1:
                return True
        return False
    for a in small_primes:
        if not trial(a):
            return False
    return True

data = sys.stdin.buffer.read().split()
it = iter(data)
T = int(next(it))
out_lines = []
for _ in range(T):
    n = int(next(it))
    out_lines.append('Yes' if is_probable_prime(n) else 'No')
sys.stdout.write('\n'.join(out_lines))

算法及复杂度

  • 算法:Miller–Rabin 确定化判素(,固定底数集合)
  • 时间复杂度:单次约 幂模次数,整体
  • 空间复杂度: