题目链接
题目大意
找出比p小的最大的素数q,输出(q!)%p
解题思路
找素数的时候就直接暴力找,判断素数用米勒拉宾算法
阶乘用威尔逊定理
网上贴的这个定义推理
然后就按着打就完了,中间用逆元求解
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long add(long long a,long long b,long long mod)
{
long long res=0;
while(b>0)
{
if(b&1)
res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
long long mod_pow(long long x,long long n,long long mod)
{
long long res=1;
while(n>0)
{
if(n&1)
res=add(res,x,mod);
x=add(x,x,mod);
n>>=1;
}
return res;
}
long long mul(long long a,long long b,long long p)
{
long long d=1;
a=a%p;
while(b>0)
{
if(b&1)
d=add(d,a,p);
a=add(a,a,p);
b>>=1;
}
return d;
}
int witness(long long a,long long n)
{
long long d=n-1;
if(n==2)
return 1;
if(!(n&1))
return 0;
while(!(d&1))
d=d/2;
long long t=mul(a,d,n);
while((d!=n-1)&&(t!=1)&&(t!=n-1))
{
t=mul(t,2,n);
d=d<<1;
}
return (t==n-1)||(d&1);
}
int F(long long x)
{
int a[3]={2,7,61};
for(int i=0;i<3;i++)
{
if(!witness(a[i],x))
return 0;
}
return 1;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
long long p,q;
scanf("%lld",&p);
for(long long i=p-1;;i--)
{
if(F(i))
{
q=i;
break;
}
}
long long res=1;
for(long long i=q+1;i<=p-2;i++)
res=add(res,i,p);
res=mod_pow(res,p-2,p);
printf("%lld\n",res);
}
return 0;
}