HDU 6608 Fansblog(素数密度+米勒罗宾+威尔逊定理)

大致题意

给定一个质数p ,求这个质数的前一个质数 q,输出 q!% p;
1e10 <= p <= 1e14

思路

因为有这么个定理 n 以内的质数的个数趋近 n/ln(n) 所以质数的密度是logn级别的。因此可以暴力的往前找,然后用Miller_Rabin判一下素数,(然后比赛中我是oeis的)
然后由威尔逊定理可以推出计算 q! %p。
参考博客的:https://blog.youkuaiyun.com/qq_40791842/article/details/97697165

在这里插入图片描述
长见识了…

代码
#include <cstdio>
#include <cstring>
#include<set>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<ctime>
#include<assert.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 32505
#define sc(x) scanf("%lld",&x)
typedef long long ll;
const int S=8;
ll mul_mod(ll a,ll b,ll c){
    a%=c;
    b%=c;
    ll ret=0;
    ll temp=a;
    while(b){
        if(b&1){
            ret+=temp;
            if(ret>c)ret-=c;
        }
        temp<<=1;
        if(temp>c)temp-=c;
        b>>=1;
    }
    return ret;
}
ll pow_mod(ll a,ll n,ll mod){
    ll ret=1;
    ll temp=a%mod;
    while(n){
        if(n&1)ret=mul_mod(ret,temp,mod);
        temp=mul_mod(temp,temp,mod);
        n>>=1;
    }
    return ret;
}
bool check(ll a,ll n,ll x,ll t){
    ll ret=pow_mod(a,x,n);
    ll last=ret;
    for(int i=1;i<=t;++i){
        ret=mul_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1)return true; // not prime
        last=ret;
    }
    if(ret!=1)return true; //prime
    else return false;  // not prime
}
bool Miller_Rabin(ll n){
    if(n<2)return false;
    if(n==2)return true;
    if((n&1)==0)return false;
    ll x=n-1;
    ll t=0;
    while((n&1)==0){x>>=1;t++;}
    srand(time(NULL));
    for(int i=0;i<S;++i){
        ll a=rand()%(n-1)+1;
        if(check(a,n,x,t))
            return false;
    }
    return true;
}
ll fastpow(ll x,ll y,ll p){
    ll ans,res;
    ans=1;res=x;
    while(y){
        if(y&1)ans=mul_mod(ans,res,p);
        res=mul_mod(res, res, p);
        y>>=1;
    }
    return ans;
}
int main(){
    ll t;sc(t);
    while(t--){
        ll n;sc(n);
        ll ans=1;
        for(ll i=n-2;i>=1;i--){
            if(Miller_Rabin(i)){
                printf("%lld\n",fastpow(ans,n-2,n));
                break;
            }else{
                ans=mul_mod(ans,i,n);
            }
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值