大致题意
给定一个质数p ,求这个质数的前一个质数 q,输出 q!% p;
1e10 <= p <= 1e14
思路
因为有这么个定理 n 以内的质数的个数趋近 n/ln(n) 所以质数的密度是logn级别的。因此可以暴力的往前找,然后用Miller_Rabin判一下素数,(然后比赛中我是oeis的)
然后由威尔逊定理可以推出计算 q! %p。
参考博客的:https://blog.youkuaiyun.com/qq_40791842/article/details/97697165
长见识了…
代码
#include <cstdio>
#include <cstring>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<ctime>
#include<assert.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 32505
#define sc(x) scanf("%lld",&x)
typedef long long ll;
const int S=8;
ll mul_mod(ll a,ll b,ll c){
a%=c;
b%=c;
ll ret=0;
ll temp=a;
while(b){
if(b&1){
ret+=temp;
if(ret>c)ret-=c;
}
temp<<=1;
if(temp>c)temp-=c;
b>>=1;
}
return ret;
}
ll pow_mod(ll a,ll n,ll mod){
ll ret=1;
ll temp=a%mod;
while(n){
if(n&1)ret=mul_mod(ret,temp,mod);
temp=mul_mod(temp,temp,mod);
n>>=1;
}
return ret;
}
bool check(ll a,ll n,ll x,ll t){
ll ret=pow_mod(a,x,n);
ll last=ret;
for(int i=1;i<=t;++i){
ret=mul_mod(ret,ret,n);
if(ret==1&&last!=1&&last!=n-1)return true; // not prime
last=ret;
}
if(ret!=1)return true; //prime
else return false; // not prime
}
bool Miller_Rabin(ll n){
if(n<2)return false;
if(n==2)return true;
if((n&1)==0)return false;
ll x=n-1;
ll t=0;
while((n&1)==0){x>>=1;t++;}
srand(time(NULL));
for(int i=0;i<S;++i){
ll a=rand()%(n-1)+1;
if(check(a,n,x,t))
return false;
}
return true;
}
ll fastpow(ll x,ll y,ll p){
ll ans,res;
ans=1;res=x;
while(y){
if(y&1)ans=mul_mod(ans,res,p);
res=mul_mod(res, res, p);
y>>=1;
}
return ans;
}
int main(){
ll t;sc(t);
while(t--){
ll n;sc(n);
ll ans=1;
for(ll i=n-2;i>=1;i--){
if(Miller_Rabin(i)){
printf("%lld\n",fastpow(ans,n-2,n));
break;
}else{
ans=mul_mod(ans,i,n);
}
}
}
}