Fansblog---威尔逊定理
Fansblog
题意:给一个质数\(p\),找小于\(p\)的最大质数\(q\),并求\(q!modp\). \(p,q\epsilon(10^9, 10^{14})\)
题解:威尔逊定理:一个数\(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)
代码:
#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");
}
}