威尔逊

传送门

给你一个素数p,让你求 k!%p, 其中k为比p小的整数里最大的素数。例如p=5,则k=3。p=11,则k=7。 k! = k*(k-1)*······*2*1;

Input第一行包含一个整数 T(1<=T<=10) 表示测试样例的个数.
接下来有T行,每行包含一个素数 p (1e9≤p≤1e14)
Output对于每个测试样例,输出一个整数k!%p,代表答案
Sample Input

1
1000000007

Sample Output

328400734


因为两个素数之间的间隔不会超过300,我们从P-1开始一个个查验找Q。再把(P-1)乘上[Q,P-1]的逆元即可。
注意因为数很大,所有涉及乘的地方都要用快速乘。
威尔逊定理:在初等数论中,威尔逊定理给出了判定一个自然数是否为素数充分必要条件
即:当且仅当p为素数时:( p -1 )! ≡ -1 ( mod p ),但是由于阶乘是呈爆炸增长的,其结论对于实际操作意义不大。

也就是说(P-1)!mod P == P-1;


//威尔逊定理是(P-1)!modP==P-1
//Q P
//(Q-1)!modP=-1 ==> (P-1)!mod P == P-1;
//Q!*(Q+1)*(Q+2)....(P-1)==(P-1)!
//Q!(mod P)==(P-1)!/[(Q+1)*(Q+2)*(Q+3)....(P-1)](mod P)
//Q!(mod P)==(P-1)/(Q+1)*(Q+2)*(Q+3)*...*(P-1))(mod P)

因为这里的数乘法太大了,所以用的快速乘法
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e7+100; 
int prime[maxn];
bool biaoji[maxn];
int cnt=0;
void inint(){
    for(int i=2;i<maxn;i++){
        if(!biaoji[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<maxn;j++){
            biaoji[i*prime[j]]=1;
            if(i%prime[j]==0){
                break;
            }
        }
    }
}
bool judge(ll x){
    for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++){
        if(x%prime[i]==0){
            return 0;
        }
    }
    return 1;
}
 
ll mul(ll a,ll b,ll mod){//快速乘法 
    ll ans=0;
    while(b){
        if(b&1){
            ans=(ans+a)%mod;
        } 
        a=(a+a)%mod;
        b>>=1;
    }
    return ans%mod;
}
ll qpow(ll a,ll b,ll mod){
    ll ans=1;
    while(b){
        if(b&1){
            ans=mul(ans,a,mod)%mod;
        }
        a=mul(a,a,mod)%mod;
        b>>=1;
    }
    return ans%mod;
} 
//威尔逊定理是(P-1)!modP==P-1 
//Q  P
//(Q-1)!modP=-1 ==> (P-1)!mod P == P-1;
//Q!*(Q+1)*(Q+2)....(P-1)==(P-1)!
//Q!(mod P)==(P-1)!/[(Q+1)*(Q+2)*(Q+3)....(P-1)](mod P)
//Q!(mod P)==(P-1)/(Q+1)*(Q+2)*(Q+3)*...*(P-1))(mod P)
int main(){
    int t;
    inint();
    cin>>t;
    while(t--){
        ll p;
        cin>>p;
        ll mod=p;
        ll q;
        for(q=p-1;q>=2;q--){
            if(judge(q)){
                break;
            }
        }
        ll ans=p-1;
        for(ll i=q+1;i<=p-1;i++){
            ans=(mul(ans , qpow(i,mod-2,mod) , mod));
        }
        cout<<ans<<endl;
    }
} 

 

上一篇:【网易官方】极客战记(codecombat)攻略-森林-巡逻兵克星A


下一篇:Baby-step Giant-step and its extension