• 威尔逊定理 k!%p


    传送门

    给你一个素数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;
        }
    } 
  • 相关阅读:
    Shell 批量搜索关键词并保存结果到文件中(数组、循环)
    解决tensorflow的Session Exception问题
    解决h5py的FutureWarning问题
    【转】Ubuntu16.04安装WPS
    [Linux] 随机切分文件内容
    [Python] 动态函数调用(通过函数名)
    [Python] dict字典的浅复制与深复制
    基于sklearn进行文本向量化
    Asp.Net MVC SingleServiceResolver类剖析
    Asp.Net MVC 高级特性(附带源码剖析)
  • 原文地址:https://www.cnblogs.com/lipu123/p/13991911.html
Copyright © 2020-2023  润新知