Fansblog
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
题意:
t组输入,给你一个质数数n,然后找小于n的最大的那个质数p,让你求p! %n
思路:
用到的算法如下,不会的可以先去学习一下
- Miller_Rabin
- 威尔逊定理
- 费马小定理
- 快速幂
- 快速积
首先用Miller_Rabin算法找出小于n的那个最大的素数p,结果是让你求 p! %n
根据威尔逊定理可知道 1* 2* 3*…(n-1)≡-1 (mod n)
那么 1 2* 3*…(n-1)≡n-1 (mod n)
1 2* 3*…*(n-2)≡1 (mod n)
p! *(p+1) *(p+2) *… *(n-2)≡1 (mod n)
你想要求的是 p!,那么你就要让左边的(p+1) * (p+2) *… *(n-2)这一堆东西变成1,那么此时就要用到费马小定理了让左右乘于这些数在模n意义下的的逆元就行了,在求逆元的时候要用到快速幂和快速积,之所以要用到快速积是因为相乘的两个数很大,会爆long long int 的范围
#include <bits/stdc++.h>
#include <queue>
#include <cmath>
#include <iostream>
#define ll long long
using namespace std;
long long ksj(long long a,long long b,long long mod)
{
long long ans=0;
while(b){
if(b&1)
ans=(ans+a)%mod;
a=(a*2)%mod;
b>>=1;
}
return ans%mod;
}
long long ksm(long long a,long long b,long long mod)
{
long long ans=1;
while (b)
{
if (b&1)
ans=ksj(ans,a,mod);
a=ksj(a,a,mod);
b>>=1;
}
return (ans)%mod;
}
bool check(long long a,long long n){
long long x = n - 1;
int t = 0;
while((x & 1) == 0) {
x >>= 1;
t ++;
}
x = ksm(a,x,n);
long long y;
for(int i=1;i<=t;i++) {
y = ksj(x,x,n);
if(y == 1 && x != 1 && x != n - 1) return true;
x = y;
}
if(y != 1) return true;
return false;
}
bool Miller_Rabin(long long n) {
if(n == 2) return true;
if(n == 1 || !(n & 1)) return false;
const int arr[12] = {2,3,5,7,11,13,17,19,23,29,31,37};
for(int i = 0; i < 12; i++) {
if (arr[i] >= n) break;
if(check(arr[i], n)) return false;
}
return true;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll p,n,q;
scanf("%lld",&n);
p=n-1;
while(!Miller_Rabin(p)) p--;
ll ans=1;
for(ll i=p+1;i<n-1;i++)
{
ans=ksj(ans,ksm(i,n-2,n),n);
}
printf("%lld\n",ans);
}
return 0;
}