zoukankan      html  css  js  c++  java
  • 2019HDU多校第三场F Fansblog——威尔逊定理&&素数密度

    题意

    给定一个整数 $P$($10^9 leq pleq 1^{14}$),设其前一个质数为 $Q$,求 $Q!  \% P$.

    分析

    暴力...说不定好的板子能过。

    根据威尔逊定理,如果 $p$ 为质数,则有 $(p-1)! equiv p-1(mod p)$.

    $displaystyle Q! = frac{(P-1)!}{(Q+1)(Q+2)...(p-1)} equiv  (p-1)*inv (mod P)$.

    根据素数定理,$displaystyle pi (x) sim frac{x}{lnx}$,其中 $pi (x)$ 表示不超过 $x$ 的素数的个数。直观的看,$x$ 越大,素数密度越大,接近线性。

    在题给的范围,两个相邻素数通常只隔几十个数。

    为了快速找到前一个质数,这里使用了Miller-Rabin素数测试算法(虽然题目 $sqrt n$ 也能过

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long int ll;
    
    ll mod_mul(ll a, ll b, ll mod)
    {
        ll res = 0;
        while (b)
        {
            if (b & 1)
                res = (res + a) % mod;
            a = (a + a) % mod;
            b >>= 1;
        }
        return res;
    }
    
    ll mod_pow(ll a, ll n, ll mod)
    {
        ll res = 1;
        while (n)
        {
            if (n & 1)
                res = mod_mul(res, a, mod);
            a = mod_mul(a, a, mod);
            n >>= 1;
        }
        return res;
    }
    
    // Miller-Rabin随机算法检测n是否为素数
    bool Miller_Rabin(ll n)
    {
        if (n == 2)
            return true;
        if (n < 2 || !(n & 1))
            return false;
        ll m = n - 1, k = 0;
        while (!(m & 1))
        {
            k++;
            m >>= 1;
        }
        for (int i = 1; i <= 10; i++)  // 20为Miller-Rabin测试的迭代次数
        {
            ll a = rand() % (n - 1) + 1;
            ll x = mod_pow(a, m, n);
            ll y;
            for (int j = 1; j <= k; j++)
            {
                y = mod_mul(x, x, n);
                if (y == 1 && x != 1 && x != n - 1)
                    return false;
                x = y;
            }
            if (y != 1)
                return false;
        }
        return true;
    }
    
    ll mul(ll a, ll b, ll p)
    {
        ll res = 1;
        for(ll i = a;i <= b;i++)  res = mod_mul(res, i, p);
        return res;
    }
    
    ll p, q;
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            scanf("%lld", &p);
            q = p-1;
            while(!Miller_Rabin(q))  q--;
            ll inv = mod_pow(mul(q+1, p-1, p), p-2, p);
            ll ans = mod_mul(p-1, inv, p);
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    C# 网络编程之基于SMTP发送电子邮件
    C#实现邮件发送的功能
    Java发邮件基础篇
    java发送邮件高级篇
    Windows下bat脚本自动发邮件
    Python发送QQ邮件
    信息系统项目管理师EV、PV、AC、BAC、CV、SV、EAC、ETC、CPI、SPI概念说明
    DOS命令整理
    JAVA对时间的操作
    JAVA 调用HTTP接口POST或GET实现方式(转)
  • 原文地址:https://www.cnblogs.com/lfri/p/11273277.html
Copyright © 2011-2022 走看看