Fansblog
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
思路
题目的意思是,给出一个素数P,让我们找出小于n的最大素数Q。首先数字非常大,10的9次方~10的14次方,不可能暴力判断素性,百度发现有一种算法叫做:米勒-拉宾素性检验 ,据说在1014以内最大素数间隔是777,那么直接从给出的素数往前逐个进行米勒拉宾素性检验就行了。找到需要的Q之后,发现需要阶乘,即使是范围内最小的数两个相乘也会炸,所以需要别的办法。
根据威尔逊定理,当P为质数,有 (P − 1) ! ≡ P − 1(mod P),则有:
(P−1) (P−2)…(Q+1) Q ! ≡ P − 1 (mod P) (P - 1) (P - 2)…(Q + 1) Q ! ≡ P − 1 (mod P)
那么只需要求得(P − 1) (P − 2)…(Q + 1) (P - 1)(P - 2)…(Q + 1) (P − 1) (P − 2)…(Q + 1) 在mod P下的逆元,再乘以P − 1,即可得到Q !
当然了,上面说的,我一点都不懂,全是复制的,所以只能在这里贴一下kuangbin模板,然后借鉴大佬的代码把后面所需的阶乘取模改出来了。
Miller_Rabin 算法进行素数测试模板
//特点:速度快、可以判断一个 < 2^63 的数是不是素数
const int S = 8; //随机算法判定次数一般 8~10 就够了
//计算 ret = (a * b) % c a,b,c < 2^63
ll mult_mod(ll a, ll b, ll c) {
a %= c;
b %= c;
ll ret = 0;
ll tmp = a;
while(b) {
if(b & 1) {
ret += tmp;
if(ret > c) {
ret -= c; //直接取模慢很多
}
}
tmp <<= 1;
if(tmp > c) {
tmp -= c;
}
b>>=1;
}
return ret;
}
//计算 ret = (a^n) % mod
ll pow_mod(ll a, ll n, ll mod) {
ll ret = 1;
ll temp = a % mod;
while(n) {
if(n & 1) {
ret = mult_mod(ret,temp,mod);
}
temp = mult_mod(temp,temp,mod);
n >>= 1;
}
return ret;
}
//通过a^(n-1)=1(mod n)来判断 n 是不是素数
//n-1 = x*2^t 中间使用二次判断
//是合数返回true,不一定是合数返回false
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 = mult_mod(ret,ret,n);
if(ret == 1 && last != 1 &&last != n-1) {
return true;
}
last = ret;
}
if(ret != 1) {
return true;
} else {
return false;
}
}
//Miller_Rabin算法
//是素数返回true(可能是伪素数)
//不是素数返回false
bool Miller_Rabin(ll n) {
if(n < 2) {
return false; //1、0和负数都不是素数
}
if(n == 2) {
return true; //2是素数
}
if((n & 1) == 0) {
return false; //除了2的偶数都不是素数
}
ll x = n - 1;
ll t = 0;
while((x & 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;
}
本题代码
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 0+5;
typedef long long ll;
ll t,p,q;
const int S = 8; //随机算法判定次数一般 8~10 就够了
//计算 ret = (a * b) % c a,b,c < 2^63
ll mult_mod(ll a, ll b, ll c) {
a %= c;
b %= c;
ll ret = 0;
ll tmp = a;
while(b) {
if(b&1) {
ret += tmp;
if(ret > c) {
ret -= c; //直接取模慢很多
}
}
tmp <<= 1;
if(tmp > c) {
tmp -= c;
}
b >>= 1;
}
return ret;
}
//计算 ret = (a^n) % mod
ll pow_mod(ll a, ll n, ll mod) {
ll ret = 1;
ll temp = a % mod;
while(n) {
if(n&1) {
ret = mult_mod(ret,temp,mod);
}
temp = mult_mod(temp,temp,mod);
n >>= 1;
}
return ret;
}
//通过a^(n-1)=1(mod n)来判断 n 是不是素数
//n-1 = x*2^t 中间使用二次判断
//是合数返回true,不一定是合数返回false
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 = mult_mod(ret,ret,n);
if(ret == 1 && last != 1 && last != n-1) {
return true;
}
last = ret;
}
if(ret != 1) {
return true;
} else {
return false;
}
}
//Miller_Rabin算法
//是素数返回true(可能是伪素数)
//不是素数返回false
bool Miller_Rabin(ll n) {
if(n < 2) {
return false; //1、0和负数都不是素数
}
if(n == 2) {
return true; //2是素数
}
if((n&1) == 0) {
return false; //除了2的偶数都不是素数
}
ll x = n - 1;
ll t = 0;
while((x&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 solve() {
if(q == p-2) {
return 1;
}
ll x = 1;
for(ll i=q+1; i<=p-2; i++) {
x = mult_mod(x,i,p);
}
return 1l * pow_mod(x,p-2,p);
}
int main() {
while(cin >> t) {
while(t--) {
cin >> p;
for(ll i=p-1; i>0; i--) {
if(Miller_Rabin(i)) {
q = i;
break;
}
}
cout << solve() << endl;
}
}
}