题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6608
题目大意:给定一个素数P, 求 (Q !)%P , Q是小于P的最大素数
先说说两个定理
威尔逊定理:
当且仅当p为素数时:( p -1 )! ≡ -1 ( mod p ),是判断p是否是素数的充要条件。
费马小定理
如果p是一个质数,而整数a不是p的倍数,则有a(p-1) ≡ 1(mod p)。
再说一下逆元的概念
逆元
已知P为质数,且A和P互质, 如果A * B ≡ 1(mod p)因此在%P的情况下,除A就等于乘B,B就是A的逆元。
思路
首先根据威尔逊定理,我们可以知道 ( P -1 )! ≡ -1 ( mod P ),即:
( P -1 )! ≡ P-1 ( mod P )
因此不妨先将答案置为P -1,再除去Q+1到P-1的数的乘积。
接下来先找Q,这里Q直接从P-1开始暴力往下找(本来想用的筛法,但是P太大了,只能从P-1往下找)挨个判断是否是素数,直到找到第一个素数,就是Q了,接下来就挨个除去Q+1到P-1的数(乘上他们%P条件下的逆元),由费马小定理可以知道 对于 Q-1<=X<=P-1 ,X满足X(p-1) ≡ 1(mod p),即:
X*X(p-2) ≡ 1(mod p)
所以X的逆元就是X(p-2) (%P条件下),X(p-2) 的值用快速幂求出,注意在快速幂中相乘那一块可能会溢出long long,应该先强制转化乘long double处理。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ms(a, x) memset(a, x, sizeof(a))
#define fore(i, a, n) for (long long i = a; i < n; i++)
#define ford(i, a, n) for (long long i = n - 1; i >= a; i--)
#define si(a) scanf("%d", &a)
#define sl(a) scanf("%lld", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define debug(a) cout << a << endl
#define pr(a) printf("%d ",a)
#define endl '\n'
#define pi acos(-1.0)
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define ull unsigned long long
#define ll long long
const double eps = 1e-8;
inline int sgn(const double &x) { return x < -eps ? -1 : x > eps; }
const int inf=0x3f3f3f3f;
const int MAXN = 5e5+5;
ll Mo(ll a, ll b ,ll mode)
{
//这里会溢出long long,所以一定要用long double处理
return (a*b-(ll)((long double)a*b/mode)*mode+mode)% mode;
}
ll Qpow(ll a,ll b,ll mode)
{
ll ans=1;
while(b)
{
if(b&1)ans=Mo(ans,a,mode);
b>>=1;
a=Mo(a,a,mode);
}
return ans;
}
bool check(ll x)
{
for(ll i=2;i*i<=x;++i)
{
if(x%i==0)
return false;
}
return true;
}
void solve()
{
ll p;
sl(p);
ll q;
for(ll i=p-1;;i--)
{
if(check(i)){
q=i;break;
}
}
ll ans=p-1;
for(ll i=q+1;i<=p-1;++i)
{
ans=Mo(ans,(ll)(Qpow(i,p-2,p)),p);
}
cout<<ans<<endl;
return;
}
int main()
{
int t;
si(t);
while(t--)solve();
return 0;
}