Where_Free

羸弱 无知 自大 懒惰

HDU6608-Fansblog(Miller_Rabbin素数判定,威尔逊定理应用,乘法逆元)

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
 

 

Source

题意:

找出Q,Q为比P小的数中的最大素数,求Q!

题解:

用Miller_Rabbin素数检测快速找出Q,用威尔逊定理 ,求出(P-1)! 

根据乘法逆元,用除的模求出Q!

Code:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <time.h>
  4 using namespace std;
  5 /**
  6 Miller_Rabin 算法进行素数测试
  7 快速判断一个<2^63的数是不是素数,主要是根据费马小定理
  8 */
  9 #define ll __int128
 10 const int S=8; ///随机化算法判定次数
 11 ll MOD;
 12 ///计算ret=(a*b)%c  a,b,c<2^63
 13 ll mult_mod(ll a,ll b,ll c)
 14 {
 15     a%=c;
 16     b%=c;
 17     ll ret=0;
 18     ll temp=a;
 19     while(b)
 20     {
 21         if(b&1)
 22         {
 23             ret+=temp;
 24             if(ret>c)
 25                 ret-=c;//直接取模慢很多
 26         }
 27         temp<<=1;
 28         if(temp>c)
 29             temp-=c;
 30         b>>=1;
 31     }
 32     return ret;
 33 }
 34 
 35 ///计算ret=(a^n)%mod
 36 ll pow_mod(ll a,ll n,ll mod)
 37 {
 38     ll ret=1;
 39     ll temp=a%mod;
 40     while(n)
 41     {
 42         if(n&1)
 43             ret=mult_mod(ret,temp,mod);
 44         temp=mult_mod(temp,temp,mod);
 45         n>>=1;
 46     }
 47     return ret;
 48 }
 49 
 50 ///通过费马小定理 a^(n-1)=1(mod n)来判断n是否为素数
 51 ///中间使用了二次判断,令n-1=x*2^t
 52 ///是合数返回true,不一定是合数返回false
 53 bool check(ll a,ll n,ll x,ll t)
 54 {
 55     ll ret=pow_mod(a,x,n);
 56     ll last=ret;//记录上一次的x
 57     for(int i=1;i<=t;i++)
 58     {
 59         ret=mult_mod(ret,ret,n);
 60         if(ret==1&&last!=1&&last!=n-1)
 61             return true;//二次判断为是合数
 62         last=ret;
 63     }
 64     if(ret!=1)
 65         return true;//是合数,费马小定理
 66     return false;
 67 }
 68 
 69 
 70 ///Miller_Rabbin算法
 71 ///是素数返回true(可能是伪素数),否则返回false
 72 bool Miller_Rabbin(ll n)
 73 {
 74     if(n<2) return false;
 75     if(n==2) return true;
 76     if((n&1)==0) return false;//偶数
 77     ll x=n-1;
 78     ll t=0;
 79     while((x&1)==0)
 80     {
 81         x>>=1;
 82         t++;
 83     }
 84     srand(time(NULL));
 85     for(int i=0;i<S;i++)
 86     {
 87         ll a=rand()%(n-1)+1; // 生成随机数 0<a<=n-1  去试试
 88         if(check(a,n,x,t))
 89             return false;
 90     }
 91     return true;
 92 }
 93 
 94 //------------------------------------------------------------------------求素数
 95 inline ll pow(const ll n, const ll k) {
 96     ll ans = 1;
 97     for (ll num=n,t=k;t;num=num*num%MOD,t>>=1) if(t&1) ans=ans*num%MOD;
 98     return ans%MOD;
 99 }
100 
101 inline ll inv(const ll num) {
102     return pow(num, MOD - 2);
103 }
104 //求乘法逆元
105 
106 int main(){
107     ll ans;
108     int T;
109     long long a;
110     cin>>T;
111     while(T--){
112         cin>>a;
113         MOD=a;
114         a--;
115         while(!Miller_Rabbin(a)) a--;
116         ans=MOD-1;
117         for(ll i=a+1;i<=MOD-1;i++){
118             ans=(ans%MOD*inv(i)%MOD)%MOD;
119         }
120         a=ans;
121         cout<<a<<'\n';
122     }
123 }

 

posted on 2019-07-30 13:02  Where_Free  阅读(257)  评论(0编辑  收藏  举报

导航