2019HDU多校第三场F Fansblog——威尔逊定理&&素数密度

题意

给定一个整数 $P$($10^9 \leq p\leq 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\n", ans);
    }
    return 0;
}

 

posted @ 2019-07-30 22:40  Rogn  阅读(448)  评论(0)    收藏  举报