题意:给一个素数P,求小于P的第一个素数Q!% P 的值。
威尔逊定理: 即:当且仅当 p为素数时:( p -1 )! ≡ -1 ( mod p )
米勒拉宾判素数——大整数是否为素数
则找到小于P的第一个素数Q,1*....Q*...*(P-1)%P≡-1,则 1*...*Q%P ≡ -1/( (Q+1)*(Q+2)...*(P-1) )
其中除法用逆元(除以一个数取模相当于乘以这个数的 模减2 次方)求。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define l1 long long
#define ll __int128
using namespace std;
#define pi acos(-1.0)
ll add_mod(ll a,ll b,ll mod){ //快乘法 基于快速幂的二分思想
ll ans=0; //由于考虑到取模数很大 快速幂会溢出
while(b){ //必须使用该方法
if(b&1) //我这里写的是非递归版
ans=(ans+a)%mod;
a=a*2%mod;
b>>=1;
}
return ans;
}
ll quick(ll a,ll b,ll mod){
if(b==0) return 1;
ll res=1;
while(b!=1){
if(b&1) res=res*a%mod;
a=a*a%mod;
b/=2;
}
return res*a%mod;
}
bool Miller_Rabbin(ll n,ll a){//米勒拉宾素数判断函数主体
ll d=n-1,s=0,i;
while(!(d&1)){ // 先把(2^s)*d 算出来
d>>=1;
s++;
}
ll t=quick(a,d,n); //a^d取一次余判断
if(t==1 || t==-1) //一或负一则可以声明这可能是质数
return 1;
for(i=0;i<s;i++){ //不是的话继续乘上s个2
if(t==n-1) //(n-1)*(n-1)%n=1 这一步是优化
return 1;
t=add_mod(t,t,n); // 快乘
}
return 0;
}
bool is_prime(ll n){
ll i,tab[4]={3,4,7,11};//本来应该取[1,n]内任意整数
for(i=0;i<4;i++){ //但一般这几个数足以,不需要太多组测试
if(n==tab[i])
return 1; //小判断小优化~
if(!n%tab[i])
return 0;
if(n>tab[i] && !Miller_Rabbin(n,tab[i]))
return 0;
}
return 1;
}
ll gcd(ll a,ll b){
if(b==0)return a;
return gcd(b,a%b);
}
int main(){
l1 tp;
int t;
scanf("%d",&t);
while(t--){
scanf("%lld",&tp);
ll n = tp;
for(ll i=n-1;;i--){
if(is_prime(i)){
ll ans = -1;
for(ll j=i+1;j<=n-1;j++){
ans = ans*quick(j,n-2,n)%n;
}
ans=(ans+n)%n;
l1 as = ans;
printf("%lld\n",as);
break;
}
}
}
return 0;
}