let menu = ["Home", "Algorithms", "CodeHub", "VNOI Statistics"];

Overview

PAGAIN - Prime Again

solution.md

Để giảm số lần kiểm tra tính nguyên tố cần thực hiện, ta xắp sếp lại các truy vấn theo chiều tăng dần, sau đó duyệt từng truy vấn A[i], chạy hàm kiểm tra tính nguyên tố cho các số từ A[i] - 1 đến A[i-1], cho đến khi gặp số nguyên tố đầu tiên thì dừng.

Cần dùng Rabin-Miller hoặc Miller để kiểm tra cho nhanh.

Code mẫu dùng thuật toán Miller với 3 base là 2, 7 và 61.

main.cpp
Open in Github Download
#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>
using namespace std;
typedef unsigned long long ll;

ll pow(ll a, ll n, ll m) {
    ll result = 1;
    a = a % m;
    while (n > 0) {
        if (n & 1) result = result * a % m;
        n >>= 1;
        a = a * a % m;
    }
    return result;
}

bool witness_test(ll s, ll d, ll n, ll witness) {
    if (n == witness) return true;
    ll p = pow(witness, d, n);
    if (p == 1) return true;
    for (; s > 0; s--) {
        if (p == n-1) return true;
        p = p * p % n;
    }
    return false;
}

bool miller(ll n) {
    ll s, d;
    s = __builtin_ctzll(n-1);
    d = (n-1) >> s;
    return witness_test(s, d, n, 2) && witness_test(s, d, n, 7) && witness_test(s, d, n, 61);
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int T; cin >> T;
    vector<ll> inp(T);
    for (ll &x: inp) cin >> x;

    vector<ll> a = inp;
    sort(a.begin(), a.end());
    vector<ll> primes;
    primes.push_back(2);
    ll bound = primes.back() + 1;
    for (ll n: a) {
        for (ll p = n&1? n-2: n-1; p >= bound; p -= 2) {
            if (miller(p)) {
                primes.push_back(p);
                break;
            }
        }
        bound = n;
    }

    for (ll n: inp) {
        auto it = lower_bound(primes.begin(), primes.end(), n);
        it--;
        cout << *it << '\n';
    }
}

Comments