题目大意:找出小于 n 的最大素数 y,然后求 y ! m o d    n y! \mod n y!modn
题解:
根据威尔逊定理,一个数p是素数的充分必要条件是:
(
p
−
1
)
!
=
−
1
m
o
d
  
p
(p-1)! = -1 \mod p
(p−1)!=−1modp,当 p 是素数时有
(
p
−
2
)
!
=
1
m
o
d
  
p
(p - 2)! = 1 \mod p
(p−2)!=1modp,假定小于 p 的最小素数 q,先求出
(
p
−
2
)
∗
(
p
−
3
)
∗
(
p
−
4
)
∗
(
q
+
1
)
m
o
d
  
p
(p - 2) * ( p - 3) * (p - 4) * (q + 1) \mod p
(p−2)∗(p−3)∗(p−4)∗(q+1)modp,求一下逆元就是 q! mod p。
已知的素数最大间隔是777,直接倒序枚举暴力判断每一个数是不是素数。
由于相乘会爆long long,要用快速乘(黑科技O(1)快速乘)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 10;
typedef long long ll;
bool ispri[maxn];
ll pri[maxn];
long long n;
void seive(int n) {
ispri[0] = ispri[1] = true;
pri[0] = 0;
for(int i = 2; i <= n; i++) {
if(!ispri[i]) pri[++pri[0]] = i;
for(int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
ispri[i * pri[j]] = true;
if(i % pri[j] == 0) break;
}
}
}
int t;
inline long long multi(long long x,long long y,long long mod) {
long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
return tmp < 0 ? tmp + mod : tmp;
}
ll fpow(ll a,ll b,ll p) {
ll r = 1;
while(b) {
if(b & 1) r = multi(r,a,p);
a = multi(a,a,p);
b >>= 1;
}
return r;
}
int main() {
seive(1e7);
scanf("%d",&t);
ll d = 1e9,tmp;
while(t--) {
scanf("%lld",&n);
for(long long j = n - 1; j >= 1; j--) {
bool f = true;
for(int i = 1; i <= pri[0] && 1ll * pri[i] * pri[i] <= j; i++)
if(j % pri[i] == 0) {
f = false;
break;
}
if(f) {
tmp = j;
break;
}
}
ll tot = 1;
for(ll i = n - 2; i > tmp; i--)
tot = multi(tot,i,n);
printf("%lld\n",fpow(tot,n - 2,n));
}
return 0;
}