Problem Description
Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people visited this blog.One day, he find the visits has reached P , which is a prime number.He thinks it is a interesting fact.And he remembers that the visits had reached another prime number.He try to find out the largest prime number Q ( Q < P ) ,and get the answer of Q! Module P.But he is too busy to find out the answer. So he ask you for help. ( Q! is the product of all positive integers less than or equal to n: n! = n * (n-1) * (n-2) * (n-3) *… * 3 * 2 * 1 . For example, 4! = 4 * 3 * 2 * 1 = 24 )
Input
First line contains an number T(1<=T<=10) indicating the number of testcases.
Then T line follows, each contains a positive prime number P (1e9≤p≤1e14)
Then T line follows, each contains a positive prime number P (1e9≤p≤1e14)
Output
For each testcase, output an integer representing the factorial of Q modulo P.
Sample Input
1
1000000007
Sample Output
328400734
Source
题意:
找出Q,Q为比P小的数中的最大素数,求Q!
题解:
用Miller_Rabbin素数检测快速找出Q,用威尔逊定理 ,求出(P-1)!
根据乘法逆元,用除的模求出Q!
Code:
1 #include <iostream> 2 #include <algorithm> 3 #include <time.h> 4 using namespace std; 5 /** 6 Miller_Rabin 算法进行素数测试 7 快速判断一个<2^63的数是不是素数,主要是根据费马小定理 8 */ 9 #define ll __int128 10 const int S=8; ///随机化算法判定次数 11 ll MOD; 12 ///计算ret=(a*b)%c a,b,c<2^63 13 ll mult_mod(ll a,ll b,ll c) 14 { 15 a%=c; 16 b%=c; 17 ll ret=0; 18 ll temp=a; 19 while(b) 20 { 21 if(b&1) 22 { 23 ret+=temp; 24 if(ret>c) 25 ret-=c;//直接取模慢很多 26 } 27 temp<<=1; 28 if(temp>c) 29 temp-=c; 30 b>>=1; 31 } 32 return ret; 33 } 34 35 ///计算ret=(a^n)%mod 36 ll pow_mod(ll a,ll n,ll mod) 37 { 38 ll ret=1; 39 ll temp=a%mod; 40 while(n) 41 { 42 if(n&1) 43 ret=mult_mod(ret,temp,mod); 44 temp=mult_mod(temp,temp,mod); 45 n>>=1; 46 } 47 return ret; 48 } 49 50 ///通过费马小定理 a^(n-1)=1(mod n)来判断n是否为素数 51 ///中间使用了二次判断,令n-1=x*2^t 52 ///是合数返回true,不一定是合数返回false 53 bool check(ll a,ll n,ll x,ll t) 54 { 55 ll ret=pow_mod(a,x,n); 56 ll last=ret;//记录上一次的x 57 for(int i=1;i<=t;i++) 58 { 59 ret=mult_mod(ret,ret,n); 60 if(ret==1&&last!=1&&last!=n-1) 61 return true;//二次判断为是合数 62 last=ret; 63 } 64 if(ret!=1) 65 return true;//是合数,费马小定理 66 return false; 67 } 68 69 70 ///Miller_Rabbin算法 71 ///是素数返回true(可能是伪素数),否则返回false 72 bool Miller_Rabbin(ll n) 73 { 74 if(n<2) return false; 75 if(n==2) return true; 76 if((n&1)==0) return false;//偶数 77 ll x=n-1; 78 ll t=0; 79 while((x&1)==0) 80 { 81 x>>=1; 82 t++; 83 } 84 srand(time(NULL)); 85 for(int i=0;i<S;i++) 86 { 87 ll a=rand()%(n-1)+1; // 生成随机数 0<a<=n-1 去试试 88 if(check(a,n,x,t)) 89 return false; 90 } 91 return true; 92 } 93 94 //------------------------------------------------------------------------求素数 95 inline ll pow(const ll n, const ll k) { 96 ll ans = 1; 97 for (ll num=n,t=k;t;num=num*num%MOD,t>>=1) if(t&1) ans=ans*num%MOD; 98 return ans%MOD; 99 } 100 101 inline ll inv(const ll num) { 102 return pow(num, MOD - 2); 103 } 104 //求乘法逆元 105 106 int main(){ 107 ll ans; 108 int T; 109 long long a; 110 cin>>T; 111 while(T--){ 112 cin>>a; 113 MOD=a; 114 a--; 115 while(!Miller_Rabbin(a)) a--; 116 ans=MOD-1; 117 for(ll i=a+1;i<=MOD-1;i++){ 118 ans=(ans%MOD*inv(i)%MOD)%MOD; 119 } 120 a=ans; 121 cout<<a<<' '; 122 } 123 }