HDU 6608 Fansblog——————大素数检测

本文探讨了如何利用威尔逊定理快速求解最接近给定素数的另一个素数的阶乘模该素数的问题。通过逆元计算和Miller-Rabin素性测试,实现了高效准确的算法。

Fansblog

点击题目查看题面 点击这里也可以

Source
2019 Multi-University Training Contest 3


给你一个素数 P P P
让给你求最接近P的素数 Q Q Q
输出 Q ! % P Q!\%P Q!%P

根据威尔逊定理我们可以知道
当且仅当 P P P是素数时
( P − 1 ) ! % P = − 1 (P-1)!\%P=-1 (P1)!%P=1

( P − 1 ) ! % P = P − 1 (P-1)!\%P=P-1 (P1)!%P=P1

自己打个表也能发现这个规律
在这里插入图片描述

我们知道了 ( P − 1 ) ! % P = P − 1 (P-1)!\%P=P-1 (P1)!%P=P1
那么 ( Q − 1 ) ! % P = ( P − 1 ) ∗ i n v ( P − 1 ) ∗ i n v ( P − 2 ) . . . ∗ i n v ( Q + 1 ) ∗ i n v ( Q ) (Q-1)!\%P=(P-1)*inv(P-1)*inv(P-2)...*inv(Q+1)*inv(Q) (Q1)!%P=(P1)inv(P1)inv(P2)...inv(Q+1)inv(Q)
所以我们就可以在很快的时间里得到结果

/*--------- Hongjie ----------*/
// #include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<bitset>
#include<set>
#include<vector>
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int cnt=3,tab[5]={2,3,7,61};
ll T,Q,P;
ll n,m;
ll Mul(ll x,ll y,ll mod){
    ll ans=(x*y-(ll)((long double)x/mod*y+0.5)*mod);
    return ans<0?ans+mod:ans;
}
ll Exp(ll x,ll y,ll mod){
    ll ans=1;
    while(y){
        if(y&1) ans=Mul(ans,x,mod);
        y>>=1;
        x=Mul(x,x,mod);
    }
    return ans;
}
bool Miller_Rabin(ll n){
    if(n==2||n==3||n==5||n==7||n==11||n==61) return 1;
    if(n==1||n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%61==0) return 0;
    For(i,0,cnt) {
        RE ll d=n-1;
        while(!(d&1)) d>>=1;
        RE ll s=Exp(tab[i],d,n);
        while(s!=1&&s!=n-1&&d!=n-1) d<<=1,s=Mul(s,s,n);
        if(s!=n-1&&!(d&1)) return 0;
    }
    return 1;
}

ll inv(ll a,ll p) {
        return Exp(a,p-2,p);
}

int main(){
        // freopen("../in.txt","r",stdin);
        // freopen("../out.txt","w",stdout);

        scanf("%I64d",&T);
        while(T--) {
                scanf("%I64d",&P);
                for(ll q=P-1;;q--)
                        if(Miller_Rabin(q)) {
                                Q = q;
                                break;
                        }
                ll ans = P-1;
                for(ll i = Q+1;i<P;++i)
                        ans = Mul(ans, inv(i,P), P);
                        // ans = ans*inv(i,P)%P;
                // cout<<ans<<endl;
                printf("%I64d\n",ans%P);
        }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值