題意:給一個質數\(p\),找小於\(p\)的最大質數\(q\),並求\(q!modp\). \(p,q\epsilon(10^9, 10^{14})\)php
題解:威爾遜定理:一個數\(n\)如果質數, 則有 \((n - 1)! \equiv n - 1 mod n\). 因而能夠先令\(ans = p - 1\), 再對\(p - 1\)到\(q\)的數對\(p\)求逆元。\(p\)到\(q\)之間的距離不會超過300,斷定一個\(10^{14}\)級別的素數能夠先用歐拉篩對\(10^{7}\)以內的素數打表(總共約\(6\times10^{6}\)個素數),這樣每次能夠用o(\(6\times10^{6}\))的時間判斷這個數是否是素數。(感謝董隊的__int128板子TUT)c++
代碼:ui
#include <bits/stdc++.h> using namespace std; typedef __int128 ll; const int maxn = 1e7 + 5; int prime[maxn]; int visit[maxn]; inline __int128 read(){ __int128 x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } inline void print(__int128 x){ if(x<0){ putchar('-'); x=-x; } if(x>9) print(x/10); putchar(x%10+'0'); } void Prime(){ for (int i = 2;i <= maxn; i++) { if (!visit[i]) { prime[++prime[0]] = i; } for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) { visit[i*prime[j]] = 1; if (i % prime[j] == 0) { break; } } } } int p[maxn], cnt; ll qpow(ll x, ll y, ll mod) { ll base = x, res = 1; while(y) { if(y & 1) res = (res * base) % mod; base = (base * base) % mod; y >>= 1; } return res; } bool isprime(ll x) { for(int i = 1; i <= cnt; i++) { if(p[i] >= x) return true; if((x % p[i]) == 0) return false; } return true; } int main() { Prime(); for(int i = 2; i < maxn; i++) if(!visit[i]) p[++cnt] = i; int T; cin >> T; while(T--) { ll n; //scanf("%I128d", &n); n = read(); ll ans = n - 1; ll i = n - 1; while(1) { if(isprime(i)) { break; } ans = (ans * qpow(i, n - 2, n)) % n; i--; } print(ans); printf("\n"); } }