zoukankan      html  css  js  c++  java
  • 威尔逊定理 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;
        }
    } 
  • 相关阅读:
    django 静态文件模版上传下载配置
    drf ModelViewSet之匹配路由参数
    Django drf序列化外键关联表ID以为字段
    Django 自关联递归序列化模块 django-rest-frame-recursive模块
    Python利用Psycopg2模块将Excel表格数据导入Postgressql
    PyTorch中view的用法
    P1113 杂务 【拓扑排序】
    P3916 图的遍历 【反向建图+DFS】
    P2814 家谱【map型的并查集】
    P1102 A-B 数对【map】
  • 原文地址:https://www.cnblogs.com/lipu123/p/13991911.html
Copyright © 2011-2022 走看看