2019HDU多校第三场F Fansblog——威尔逊定理&&素数密度
题意
给定一个整数 $P$($10^9 \leq p\leq 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\n", ans); } return 0; }
个性签名:时间会解决一切