题意
给定一个整数 $P$($10^9 leq pleq 1^{14}$),设其前一个质数为 $Q$,求 $Q! \% P$.
分析
暴力...说不定好的板子能过。
根据威尔逊定理,如果 $p$ 为质数,则有 $(p-1)! equiv p-1(mod p)$.
$displaystyle Q! = frac{(P-1)!}{(Q+1)(Q+2)...(p-1)} equiv (p-1)*inv (mod P)$.
根据素数定理,$displaystyle pi (x) sim frac{x}{lnx}$,其中 $pi (x)$ 表示不超过 $x$ 的素数的个数。直观的看,$x$ 越大,素数密度越大,接近线性。
在题给的范围,两个相邻素数通常只隔几十个数。
为了快速找到前一个质数,这里使用了Miller-Rabin素数测试算法(虽然题目 $sqrt n$ 也能过
#include<bits/stdc++.h> using namespace std; typedef long long int ll; ll mod_mul(ll a, ll b, ll mod) { ll res = 0; while (b) { if (b & 1) res = (res + a) % mod; a = (a + a) % mod; b >>= 1; } return res; } ll mod_pow(ll a, ll n, ll mod) { ll res = 1; while (n) { if (n & 1) res = mod_mul(res, a, mod); a = mod_mul(a, a, mod); n >>= 1; } return res; } // Miller-Rabin随机算法检测n是否为素数 bool Miller_Rabin(ll n) { if (n == 2) return true; if (n < 2 || !(n & 1)) return false; ll m = n - 1, k = 0; while (!(m & 1)) { k++; m >>= 1; } for (int i = 1; i <= 10; i++) // 20为Miller-Rabin测试的迭代次数 { ll a = rand() % (n - 1) + 1; ll x = mod_pow(a, m, n); ll y; for (int j = 1; j <= k; j++) { y = mod_mul(x, x, n); if (y == 1 && x != 1 && x != n - 1) return false; x = y; } if (y != 1) return false; } return true; } ll mul(ll a, ll b, ll p) { ll res = 1; for(ll i = a;i <= b;i++) res = mod_mul(res, i, p); return res; } ll p, q; int main() { int T; scanf("%d", &T); while(T--) { scanf("%lld", &p); q = p-1; while(!Miller_Rabin(q)) q--; ll inv = mod_pow(mul(q+1, p-1, p), p-2, p); ll ans = mod_mul(p-1, inv, p); printf("%lld ", ans); } return 0; }