• hdu多校第三场 1006 (hdu6608) Fansblog Miller-Rabin素性检测


    题意:

    给你一个1e9-1e14的质数P,让你找出这个质数的前一个质数Q,然后计算Q!mod P

    题解:

    1e14的数据范围pass掉一切素数筛法,考虑Miller-Rabin算法。

    米勒拉宾算法是一种判断素数的随机化算法,由于其随机性,它不能保证总是正确的,但其对于一个素数,总会返回素数的结果,对于一个合数,才有极小概率返回素数的结果(假阳性)。

    米勒拉宾算法对于单个素数的判断时间复杂度为$O(log^3n)$.(因为1e14相乘会爆longlong,模乘要写成龟速乘,因此要多一个log)

    1849年,高斯猜想,素数分布密度符合如下的公式,$pi(x) approx x/lnx$,其中$pi(x)$为不超过x的素数个数,根据这个公式,1e14以内,两个素数间隔平均只有46个左右,相当稠密了。

    因此,只需要用米勒拉宾算法从P-1一个一个判断,直到找到另一个素数Q。

    再给出一个结论,对于任意素数n,(n-2)! mod n = 1,因为从2到n-2,互为模n逆元的数捉对出现,证明可参考离散数学课本数论部分。

    因此,计算Q! mod P只需计算 $prod^{P-2}_{i=Q+1}i$ 再利用费马小定理快速幂求逆元即可。

    需要注意,1e14相乘会爆longlong,可以用_int128,但稳妥一点的方法是用思想类似于快速幂的龟速乘。

    #include<bits/stdc++.h>
    #define Times 10 
    #define LL long long
    #define ll long long
    using namespace std;
    
    ll multi(ll a, ll b, ll m) {
        ll ans = 0; a %= m;
        while (b) {
            if (b & 1)ans = (ans + a) % m;
            a = (a + a) % m; b >>= 1;
        } return ans;
    }
    
    ll quick_mod(ll a, ll b, ll m) {
        ll ans = 1; a %= m;
        while (b) {
            if (b & 1)ans = multi(ans, a, m);
            a = multi(a, a, m); b >>= 1;
        } return ans;
    }
    
    bool Miller_Rabin(ll n) {
        if (n == 2)return true;
        if ((n < 2) || !(n & 1))return false;
        ll m = n - 1;
        ll k = 0;
        while ((m & 1) == 0) {
            k++; m >>= 1;
        }
        for (ll i = 0; i < Times; i++) {
            ll a = rand() % (n - 1) + 1;
            ll x = quick_mod(a, m, n);
            ll y = 0;
            for (ll j = 0; j < k; j++) {
                y = multi(x, x, n);
                if (y == 1 && x != 1 && x != n - 1)return false;
                x = y;
            } if (y != 1)return false;
        } return true;
    }
    
    long long quick_mul(long long x,long long y,long long mod) 
    {
        long long ans=0;
        while(y!=0){
            if(y&1==1)ans+=x,ans%=mod;
            x=x+x,x%=mod;
            y>>=1; 
        }
        return ans;
    }
    long long quick_pow(long long x,long long y,long long mod)
    {
        long long sum=1;
        while(y!=0){
             if(y&1==1)sum=quick_mul(sum,x,mod),sum%=mod;
                 x=quick_mul(x,x,mod),x%=mod;
                  y=y>>1;
        }
        return sum;
    }
    
    int main(){
    //    LL pp=1;
    //    for(int i=1;i<=999999937;i++){
    //        pp=pp*i%1000000007;
    //    } 
    //    printf("%lld
    ",pp);
        int t;
        scanf("%d",&t);
        while(t--){
            LL q;
            scanf("%lld",&q);
            LL p;
            for(register LL i=q-2;;i-=2){
                if(Miller_Rabin(i)){
                    p=i;break;
                }
            }
    //        printf("%d
    ",p);
            LL ans=1;
            
            for(LL j=p+1;j<=q-2;j++){
                ans=quick_mul(ans,j,q);
            }
            printf("%lld
    ",quick_pow(ans,q-2,q));
        }
        return 0;
    }
  • 相关阅读:
    【WPF on .NET Core 3.0】 Stylet演示项目
    【WPF on .NET Core 3.0】 Stylet演示项目
    [译]ABP v1.0终于发布了!
    Centos7 安装配置 Rabbitmq Cluster
    新系统添加sshkey/pexpect基本使用
    ansible Templates
    Jenkins Sonar
    Haproxy 安装及配置
    keepalived 安装及配置
    docker etcd
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11270257.html
Copyright © 2020-2023  润新知