HDU6608 Fansblog

本文详细解析了HDU6608 Fansblog问题的解题思路,利用威尔逊定理和费马小定理,通过Miller-Rabin素性测试算法确定小于给定素数P的最大素数Q,进而求解Q的阶乘模P的值。源码示例采用C++实现,包括快速幂和素性测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDU6608 Fansblog

题目链接

http://acm.hdu.edu.cn/showproblem.php?pid=6608

解题思路

P已知,是一个素数, 1 e 9 ≤ P ≤ 1 e 14 1e9 \le P \le1e14 1e9P1e14。Q未知,Q满足以下条件:Q是小于P的最大素数。
所以问题分两步解决:先确定Q,然后求Q的阶乘。
如何确定Q呢?只需要判断素数就行了,从P开始,依次递减,直到找到某个数是素数,这个数就是Q了。
接下来就是求 Q ! Q! Q! 了,因为Q会很大,所以不能暴力求阶乘,这里利用威尔逊定理:当且仅当P为素数时:( P -1 )! ≡ -1 ( mod P )
( P − 1 ) ! ≡ − 1 ( m o d P ) ≡ ( P − 1 ) ( m o d P ) (P-1)! \equiv -1(mod P) \equiv (P-1)(mod P) (P1)!1(modP)(P1)(modP)
所以有:
Q ! ≡ 1 ( Q + 1 ) × ( Q + 2 ) . . . ( P − 3 ) × ( P − 2 ) ( m o d P ) Q! \equiv {1 \over(Q+1) \times(Q+2)...(P-3)\times(P-2)}(mod P) Q!(Q+1)×(Q+2)...(P3)×(P2)1(modP)
≡ 1 ( Q + 1 ) × 1 ( Q + 2 ) . . . 1 ( P − 3 ) × 1 ( P − 2 ) ( m o d P ) \equiv {1 \over(Q+1) } \times{1 \over(Q+2) }... {1 \over(P-3) } \times{1 \over(P-2) }(mod P) (Q+1)1×(Q+2)1...(P3)1×(P2)1(modP)
接下来结合费马小定理求逆元:
Q ! ≡ ( Q + 1 ) P − 2 × ( Q + 2 ) P − 2 . . . ( P − 3 ) P − 2 × ( P − 2 ) P − 2 ( m o d P ) Q! \equiv (Q+1)^{P-2} \times (Q+2)^{P-2} ... (P-3)^{P-2} \times (P-2)^{P-2}(mod P) Q(Q+1)P2×(Q+2)P2...(P3)P2×(P2)P2(modP)
然后快速幂求就行了,需要注意的是,一次 ( Q + 1 ) × ( Q + 1 ) (Q+1) \times (Q + 1) (Q+1)×(Q+1) 就会爆long long,所以可以使用__int128或者快速乘来计算。
源码如下:

#include<cstdlib>
#include<ctime>
#include<cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int count=20;

ll modular_exp(ll a,ll m,ll n)
{
    if(m==0)
        return 1;
    if(m==1)
        return (a%n);
    ll w=modular_exp(a,m/2,n);
    w=(__int128)w*w%n;
    if(m&1)
        w=(__int128)w*a%n;
    return w;
} 

bool Miller_Rabin(ll n)
{
    srand(time(NULL));
    if(n==2)
        return true;
    if (n < 2 || !(n & 1)) 
        return false;
    for(int i=0;i<count;i++)
    {
        int a=rand()%(n-2)+2;
        if(modular_exp(a,n,n)!=a)
            return false;
    }
    return true;
}

ll qpow_long(ll a, ll n, ll m){
    ll res = 1;
    while(n) {
        if(n & 1)
            res = (__int128)res * a % m;
        n >>= 1;
        a = (__int128)a * a % m;
    }
    return res % m;
}

int main()
{
    int T;
    cin >> T;
    while(T--) {
        ll p;
        cin >> p;
        ll ret = 1, q = p-2;
        while(!Miller_Rabin(q)) {
            ret = (__int128)ret * qpow_long(q, p-2, p) % p;
            q--;
        }
        printf("%lld\n", ret);
    }
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值