Fansblog
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2107 Accepted Submission(s): 868
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,我们需要找出小于Q的最大的质数Q,然后求出Q!modP,进行输出即可;
解题分析:
题目上给的P的范围是(1e9≤p≤1e14),围是一看这个范围,肯定就不能用普通的方法啦,首先判断素数和素数打表就是个问题,所以说,在这里就出现了一个新的定理,就是Miller-rabin素数测试方法,可以判断特别大的数,就算是1e14的数,也是可以很快判断出来的,所以我们在这里需要用Miller-rabin去求出这个Q;
还有一个知识点,就是威尔逊定理,他内容是这样的:
所以我们代入Q!,有:
即:
但是这里需要注意,因为p-1是取模后的结果,而且数比较大,进行除法以后,精度不允许,而且计算会出错,所以我们这里只需要用p-1去乘以q+1、q+2....p-1的逆元,然后取模即可;
其中逆元的求法,用到的是费马小定理,得出n的逆元就是n的mod-2次方,所以就需要用到快速幂哦;
然后其实这里用到快速幂的话,也是有可能会超时的,所以需要用快速乘来对快速幂进行进一步的优化;
代码篇:
#include <iostream>
#define ll long long
using namespace std;
const int N = 1e7 + 10;
ll p, q, mod;
int prime[N + 10], cnt;
bool vis[N + 10];
bool is_prime(ll n) ///Miller-Rabin判断素数
{
for(ll i = 0; i < cnt && (ll)prime[i] * prime[i] <= n; i++)
{
if(n % prime[i] == 0)
return false;
}
return true;
}
void get_prime() ///素数打表
{
for(ll i = 2; i <= N; i++)
{
if(!vis[i])
prime[cnt++] = i;
for(ll j = 0; j < cnt && i * prime[j] <= N; j++)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
}
ll mul(ll res, ll k) ///快速乘
{
ll ans = 0;
while(k)
{
if(k & 1)
ans = (ans + res) % mod;
res = (res + res) % mod;
k >>= 1;
}
return ans;
}
ll poww(ll a, ll b) ///快速幂
{
ll ans = 1;
while(b)
{
if(b & 1)
ans = mul(ans, a);
a = mul(a, a);
b >>= 1;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false); ///优化cin cout
ll t, ans;
get_prime(); ///素数打表
cin >> t;
while(t--)
{
cin >> p;
ans = p - 1;
mod = p;
q = p - 1;
while(!is_prime(q)) ///求出q的值
q--;
for(ll i = q + 1; i < p; i++) ///乘上对应的逆元
ans = mul(ans, poww(i, mod - 2));
cout << ans << endl;
}
return 0;
}
OVER!