求阶乘对一个大质数取模
威尔逊定理:当p是质数时,满足
注意米勒罗宾的写法,小心溢出
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int Times = 15;
LL multi(LL a,LL b,LL mod)
{
LL ans=0;
while(b)
{
if(b&1) ans=(ans+a)%mod;
b>>=1;
a=(a%mod+a%mod)%mod;
}
return ans;
}
LL pow_mod(LL a,LL b,LL mod)
{
LL ans=1;
while(b)
{
if(b&1) ans=multi(ans,a,mod);
b>>=1;
a=multi(a,a,mod);
}
return ans;
}
bool Witness(LL a,LL n)
{
LL m = n-1;
int j=0;
while(!(m&1))
{
j++;
m>>=1;
}
LL x = pow_mod(a,m,n);
if(x==1||x==n-1)
{
return false;
}
while(j--)
{
x = multi(x,x,n);
if(x==n-1)
{
return false;
}
}
return true;
}
LL random(LL n)
{
return (LL)((double)rand()/RAND_MAX*n+0.5);
}
bool miller_rabin(LL n)
{
if(n<2) return false;
if(n==2) return true;
if(!(n&1)) return false;
for(int i=1;i<=Times;i++)
{
LL a = random(n-2)+1;
if(Witness(a,n)) return false;
}
return true;
}
LL cal(LL solve,LL n)
{
if(solve==n-2) return 1;
LL x=1;
for(LL i=solve+1;i<=n-2;i++)
{
x = multi(x,i,n);
}
return 1l*pow_mod(x,n-2,n);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
LL n;
scanf("%lld",&n);
LL solve;
for(LL i = n-1;;i--)
if(miller_rabin(i)) {
solve=i;
break;
}
// cout<<solve<<endl;
printf("%lld\n",cal(solve,n));
}
return 0;
}