威尔逊定理:在初等数论中,威尔逊定理给出了判定一个自然数是否为素数的充分必要条件。即:当且仅当p为素数时:
(
p
−
1
)
!
≡
−
1
(
m
o
d
p
)
( p -1 )! ≡ -1 ( mod p )
(p−1)!≡−1(modp),但是由于阶乘是呈爆炸增长的,其结论对于实际操作意义不大。
题意:
T
T
T组样例,每组给出一个素数
P
(
1
0
9
≤
p
≤
1
0
14
)
P(10^9≤p≤10^{14})
P(109≤p≤1014),
Q
Q
Q是
P
P
P前面的第一个素数,求
Q
!
%
P
Q!\%P
Q!%P。
思路:我们知道
(
p
−
1
)
!
%
P
=
P
−
1
(p-1)!\%P=P-1
(p−1)!%P=P−1,而
Q
!
(
m
o
d
P
)
=
(
P
−
1
)
!
(
Q
+
1
)
∗
(
Q
+
2
)
∗
.
.
.
∗
(
P
−
1
)
(
m
o
d
P
)
=
P
−
1
(
Q
+
1
)
∗
(
Q
+
2
)
∗
.
.
.
∗
(
P
−
1
)
Q!(modP)=\frac{(P-1)!}{(Q+1)*(Q+2)*...*(P-1)}(modP)=\frac{P-1}{(Q+1)*(Q+2)*...*(P-1)}
Q!(modP)=(Q+1)∗(Q+2)∗...∗(P−1)(P−1)!(modP)=(Q+1)∗(Q+2)∗...∗(P−1)P−1,然后求逆元,乘起来就好了。数比较大,超过ll,要开快速乘。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e7 + 10;
ll prime[N], cnt, t, p, q;
bool vis[N + 10];
bool isP(ll x) {
for(int i = 0; i < cnt && prime[i]*prime[i] <= x; i++)
if(x % prime[i] == 0)
return 0;
return 1;
}
void get_P() {
for(int i = 2; i <= N; i++) {
if(!vis[i])
prime[cnt++] = i;
for(int j = 0; j < cnt && (ll)i * prime[j] <= N; j++) {
vis[i * prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
}
ll mul(ll a, ll b) {
ll ans = 0;
while(b) {
if(b & 1)
ans = (ans + a) % p;
b >>= 1;
a = (a + a) % p;
}
return ans;
}
ll Q(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() {
get_P();
cin >> t;
while(t--) {
cin >> p;
q = p - 1;
while(!isP(q))
q--;
ll ans = p - 1;
for(ll i = q + 1; i <= p - 1; i++)
ans = mul(ans, Q(i, p - 2));
cout << ans << endl;
}
return 0;
}