zoukankan      html  css  js  c++  java
  • 素数阶乘取余—(威尔逊定理)

    传送门

    给你一个素数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,代表答案

    要做这个题一定要先知道威尔逊定理:

     也就是说,[ (p-1)! mod p] == (p-1)

    //威尔逊定理是(P-1)!modP==P-1
    //Q P                  P是输入的的素数,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)

    因为两个素数之间的间隔不会超过3000,我们从P-1开始一个个查验找Q。再把(P-1)乘上[Q,P-1]的逆元即可。注意因为数很大,所有涉及乘的地方都要用快速乘。

    #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;
        }
    } 
  • 相关阅读:
    7年Java后端被淘汰,一路北漂辛酸史。。。
    vue jqury如何获取元素中的属性
    02-Elenment 引入使用
    01
    vuex 全局store,前后端交互
    五分钟搞懂Vuex
    VueX 的使用
    vue解决前后端跨域问题
    rest_framework/api.html
    Vue中使用markdown
  • 原文地址:https://www.cnblogs.com/lipu123/p/13961694.html
Copyright © 2011-2022 走看看