2019杭电多校第三场 6608 Fansblog(威尔逊定理+miller_rabin素性测试)

Problem Description
传送门
Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people visited this blog.One day, he find the visits has reached P , which is a prime number.He thinks it is a interesting fact.And he remembers that the visits had reached another prime number.He try to find out the largest prime number Q ( Q < P ) ,and get the answer of Q! Module P.But he is too busy to find out the answer. So he ask you for help. ( Q! is the product of all positive integers less than or equal to n: n! = n * (n-1) * (n-2) * (n-3) *… * 3 * 2 * 1 . For example, 4! = 4 * 3 * 2 * 1 = 24 )

Input
First line contains an number T(1<=T<=10) indicating the number of testcases.
Then T line follows, each contains a positive prime number P (1e9≤p≤1e14)

Output
For each testcase, output an integer representing the factorial of Q modulo P.

Sample Input
1
1000000007

Sample Output
328400734

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
#include<stdlib.h>
#include<time.h>
using namespace std;

typedef long long ll;

ll qmul(ll a,ll b,ll mod){
    ll res=0;
    while(b>0){
        if(b&1)res=(res+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return res;
}

ll mod_pow(ll x,ll n,ll mod){
    ll res=1;
    while(n>0){
        if(n&1)res=qmul(res,x,mod);
        x=qmul(x,x,mod);
        n>>=1;
    }
    return res;
}

ll random(ll n){
    return (double)rand()/RAND_MAX*n;
}

bool miller_rabin(ll n){
    if(n==2)return true;
    if(n<2||n%2==0)return false;
    ll p=n-1;
    int k=0;
    while(p%2==0){
        p/=2;k++;
    }
    for(int i=0;i<10;i++){
        ll a=random(n-2)+1;
        ll x=mod_pow(a,p,n),y;
        for(int j=0;j<k;j++){
            y=qmul(x,x,n);
            if(y==1&&x!=1&&x!=n-1)return false;
            x=y;
        }
        if(y!=1)return false;
    }
    return true;
}

ll Q,P;

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&P);
        for(ll i=P-1;;i--){
            if(miller_rabin(i)){
                Q=i;break;
            }
        }
        ll res=1;
        for(ll i=Q+1;i<=P-2;i++){
            res=qmul(res,i,P);
        }
        res=mod_pow(res,P-2,P);
        printf("%lld\n",res);
    }
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值