一、威尔逊定理内容及证明
内容
ppp 质数当且仅当 (p−1)!≡−1(modp)(p-1)!\equiv-1\pmod p(p−1)!≡−1(modp) 。
证明
(1)充分性
即 ppp 是质数,则 (p−1)!≡−1(modp)(p-1)!\equiv-1\pmod p(p−1)!≡−1(modp) 。
我们知道,在模奇素数 ppp 的剩余系下,111 到 p−1p-1p−1 的逆元都存在。考虑到 xx−1≡1(modp)xx^{-1}\equiv 1\pmod pxx−1≡1(modp) ,原式可化简为:
(p−1)!=Πi−1≠ii×Πi−1=ii≡Πi−1=ii(modp)
(p-1)!= \Pi_{i^{-1}\neq i} i\times \Pi_{i^{-1}=i}i\equiv\Pi_{i^{-1}=i}i\pmod p
(p−1)!=Πi−1=ii×Πi−1=ii≡Πi−1=ii(modp)
因此需要考虑哪些数的逆元是其本身,即满足二次剩余 x2≡1(modp)x^2\equiv1\pmod px2≡1(modp) 。移向后因式分解可得
(x−1)(x+1)≡0(modp)
(x-1)(x+1)\equiv0\pmod p
(x−1)(x+1)≡0(modp)
解得 x=±1x=\pm1x=±1 。
在 111 到 p−1p-1p−1 这 p−1p-1p−1 个数中,除了 111 和 p−1p-1p−1 的逆元是本身外,对于 ∀x∈[2,p−2],∃y∈[2,p−2]\forall x\in [2,p-2],\exist y\in [2,p-2]∀x∈[2,p−2],∃y∈[2,p−2] 满足 xy≡1(modp)xy\equiv 1\pmod pxy≡1(modp) 且 y≠xy\neq xy=x 。
综上,Πi−1=ii=1×(p−1)≡−1(modp)\Pi_{i^{-1}=i}i=1\times(p-1)\equiv-1\pmod pΠi−1=ii=1×(p−1)≡−1(modp) 。
(2)必要性
即 (p−1)!≡−1(modp)(p-1)!\equiv-1\pmod p(p−1)!≡−1(modp),则 ppp 是质数。直接证明有些困难,因此采用反证法,假设 ppp 满足条件且为合数,推出矛盾“任何合数都不可能满足这个条件”。
① p=1p=1p=1
此时 (p−1)!=0!=1≡0(mod1)(p-1)!=0!=1\equiv0\pmod 1(p−1)!=0!=1≡0(mod1) ,不满足上述条件。
② p=4p=4p=4
此时 (p−1)!=3!=6≡2(mod4)(p-1)!=3!=6\equiv2\pmod 4(p−1)!=3!=6≡2(mod4) ,不满足上述条件。
③ p>4p>4p>4 且 ppp 是完全平方数
不妨设 p=k2p=k^2p=k2 ,显然 k>2k>2k>2 。做差易得 p>2kp>2kp>2k 。
那么有
(p−1)!=1×⋯×k×⋯×2k×⋯×(p−1)=2k2×(… )
(p-1)!=1\times \dots\times k\times\dots\times2k\times \dots\times (p-1)=2k^2\times(\dots)
(p−1)!=1×⋯×k×⋯×2k×⋯×(p−1)=2k2×(…)
为 ppp 的整数倍,因此 (p−1)!≡0(modp)(p-1)!\equiv0\pmod p(p−1)!≡0(modp) 。
④ p>4p>4p>4 且 ppp 不是完全平方数
由于 ppp 不是完全平方数且不是质数,不妨设 p=a×b,a<bp=a\times b,a< bp=a×b,a<b 。
那么有
(p−1)!=1×⋯×a×⋯×b×⋯×(p−1)=(a×b)×(… )
(p-1)!=1\times\dots\times a\times\dots\times b\times \dots\times(p-1)=(a\times b)\times(\dots)
(p−1)!=1×⋯×a×⋯×b×⋯×(p−1)=(a×b)×(…)
为 ppp 的整数倍,因此 (p−1)!≡0(modp)(p-1)!\equiv0\pmod p(p−1)!≡0(modp) 。
二、例题和代码
(1) HDU2973 YAPTCHA
题目大意:
共 TTT 组数据,求
∑k=1n⌊(3k+6)!+1(3k+7)−⌊(3k+6)!(3k+7)⌋⌋
\sum_{k=1}^{n}\Big\lfloor\frac{(3k+6)!+1}{(3k+7)}-\big\lfloor\frac{(3k+6)!}{(3k+7)}\big\rfloor\Big\rfloor
k=1∑n⌊(3k+7)(3k+6)!+1−⌊(3k+7)(3k+6)!⌋⌋
的值(T,n⩽106T,n\leqslant10^6T,n⩽106)。
题解
威尔逊定理模板题。
令 3k+7=x3k+7=x3k+7=x 得:
原式=∑k=1n⌊(x−1)!+1x−⌊(x−1)!x⌋⌋
原式=\sum_{k=1}^{n}\Big\lfloor\frac{(x-1)!+1}{x}-\big\lfloor\frac{(x-1)!}{x}\big\rfloor\Big\rfloor
原式=k=1∑n⌊x(x−1)!+1−⌊x(x−1)!⌋⌋
当 xxx 为质数时,根据威尔逊定理有 (x−1)!≡−1(modx)(x-1)!\equiv -1\pmod x(x−1)!≡−1(modx) ,即 (x−1)!+1≡0(modx)(x-1)!+1\equiv0\pmod x(x−1)!+1≡0(modx) ,故 x∣(x−1)!+1x\mid(x-1)!+1x∣(x−1)!+1 ,因此
(x−1)!+1x−⌊(x−1)!x⌋=1
\frac{(x-1)!+1}{x}-\big\lfloor\frac{(x-1)!}{x}\big\rfloor=1
x(x−1)!+1−⌊x(x−1)!⌋=1
当 xxx 不是质数时,在证明威尔逊定理的必要性时有 ∀x>4,(x−1)!≡0(modx)\forall x > 4,(x-1)!\equiv0\pmod x∀x>4,(x−1)!≡0(modx) ,因此 x∣(x−1)!x\mid(x-1)!x∣(x−1)! ,因此
⌊(x−1)!+1x−⌊(x−1)!x⌋⌋=0
\Big\lfloor\frac{(x-1)!+1}{x}-\big\lfloor\frac{(x-1)!}{x}\big\rfloor\Big\rfloor=0
⌊x(x−1)!+1−⌊x(x−1)!⌋⌋=0
综上,所求的式子可以化简为
原式=∑k=1n[x is prime]=∑k=1n[3k+7 is prime]
原式=\sum_{k=1}^{n}\big[x\text{ is prime}\big]=\sum_{k=1}^{n}[3k+7\text{ is prime}]
原式=k=1∑n[x is prime]=k=1∑n[3k+7 is prime]
使用筛法筛出素数后统计前缀和即可,代码如下。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e6 + 10;
bool vist[maxn];
int cnt;
int sum[maxn], prime[maxn];
int T, n;
void Euler(int n){
vist[1] = true;
for (int i = 2; i <= n; i ++){
if (!vist[i]) prime[++ cnt] = i;
for (int j = 1; j <= cnt && i * prime[j] <= n; j ++){
vist[i * prime[j]] = true;
if (prime[j] % i == 0) break;
}
}
for (int i = 1; i < maxn; i ++) sum[i] = sum[i - 1] + (vist[3 * i + 7] == 0);
}
int main(){
Euler(maxn - 1);
cin >> T;
while (T --){
cin >> n;
cout << sum[n] << endl;
}
return 0;
}
(2) HDU6608
题目大意:
共 TTT 组数据,给定质数 ppp ,求小于 ppp 的最大质数 qqq 并求下式的值(T⩽10,109⩽p⩽1014T\leqslant 10,10^9\leqslant p\leqslant 10^{14}T⩽10,109⩽p⩽1014)。
q! mod p
q! \bmod p
q!modp
题解
由威尔逊定理
(p−1)!≡−1(modp)
(p-1)!\equiv-1\pmod p
(p−1)!≡−1(modp)
推导得
q!×(q+1)×(q+2)×⋯×(p−1)≡−1(modp)
q!\times(q+1)\times(q+2)\times\dots\times (p-1)\equiv-1\pmod p
q!×(q+1)×(q+2)×⋯×(p−1)≡−1(modp)
q!≡−(q+1)−1(q+2)−1×⋯×(p−1)−1(modp)
q!\equiv-(q+1)^{-1}(q+2)^{-1}\times\dots\times(p-1)^{-1}\pmod p
q!≡−(q+1)−1(q+2)−1×⋯×(p−1)−1(modp)
因此从 p−1p-1p−1 开始倒序枚举,使用朴素的质数检验方法检验是否为质数并记录逆元的累乘,枚举到质数就输出并停止。不过观察到数据范围比较大,因此需要使用龟速乘,代码如下。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 5;
bool vist[maxn];
int cnt;
int prime[1000005];
void Euler(int n){
for (int i = 2; i <= n; i ++){
if (!vist[i]) prime[++ cnt] = i;
for (int j = 1; j <= cnt && i * prime[j] <= n; j ++){
vist[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
}
int T;
long long n;
bool is_prime(long long x){
for (int i = 1; i <= cnt && prime[i] * prime[i] <= x; i ++)
if (x % prime[i] == 0) return false;
return true;
}
long long sMul(long long a, long long b, long long MOD){
long long ans = 0;
while (b){
if (b & 1) ans = (ans + a) % MOD;
a = (a + a) % MOD;
b >>= 1;
}
return ans;
}
long long qPow(long long a, long long b, long long MOD){
long long ans = 1;
while (b){
if (b & 1) ans = sMul(ans, a, MOD);
a = sMul(a, a, MOD);
b >>= 1;
}
return ans;
}
long long get_inv(long long a, long long p){
return qPow(a, p - 2, p);
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
Euler(maxn - 1);
cin >> T;
while (T --){
cin >> n;
long long ans = n - 1;
for (long long i = n - 1; ; i --){
bool ret = is_prime(i);
if (ret){
cout << ans << '\n';
break;
}
ans = sMul(ans, get_inv(i, n), n);
}
}
return 0;
}