Fansblog 【多校3 HDU 6608】【米勒拉宾+威尔逊定理】

本文介绍了一种算法,用于找出小于给定数的最大素数,并利用米勒拉宾算法和威尔逊定理计算该素数阶乘模给定数的结果。通过暴力搜索和逆元求解,实现了高效计算。

题目链接

题目大意

找出比p小的最大的素数q,输出(q!)%p

解题思路

找素数的时候就直接暴力找,判断素数用米勒拉宾算法
阶乘用威尔逊定理

网上贴的这个定义推理
然后就按着打就完了,中间用逆元求解

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

long long add(long long a,long long b,long long mod)
{
    long long res=0;
    while(b>0)
    {
        if(b&1)
            res=(res+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return res;
}
long long mod_pow(long long x,long long n,long long mod)
{
    long long res=1;
    while(n>0)
    {
        if(n&1)
            res=add(res,x,mod);
        x=add(x,x,mod);
        n>>=1;
    }
    return res;
}
long long mul(long long a,long long b,long long p)
{
    long long d=1;
    a=a%p;
    while(b>0)
    {
        if(b&1)
            d=add(d,a,p);
        a=add(a,a,p);
        b>>=1;
    }
    return d;
}
int witness(long long a,long long n)
{
    long long d=n-1;
    if(n==2)
        return 1;
    if(!(n&1))
        return 0;
    while(!(d&1))
        d=d/2;
    long long t=mul(a,d,n);
    while((d!=n-1)&&(t!=1)&&(t!=n-1))
    {
        t=mul(t,2,n);
        d=d<<1;
    }
    return (t==n-1)||(d&1);
}
int F(long long x)
{
    int a[3]={2,7,61};
    for(int i=0;i<3;i++)
    {
        if(!witness(a[i],x))
            return 0;
    }
    return 1;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long p,q;
        scanf("%lld",&p);
        for(long long i=p-1;;i--)
        {
            if(F(i))
            {
                q=i;
                break;
            }
        }
        long long res=1;
        for(long long i=q+1;i<=p-2;i++)
            res=add(res,i,p);
        res=mod_pow(res,p-2,p);
        printf("%lld\n",res);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值