威尔逊定理
一、威尔逊定理
1、定义:对于所有的素数都有:\((p-1)! \ \equiv \ (-1) \ (mod \ p) \ \equiv \ (p-1) \ (mod \ p)\) 。
2、应用:
我们令 \(f(n,p)=(n!)_{p}\) 为所有小于等于 \(n\) 但不能被 \(p\) 整除的正整数额乘积,即 \((n!)_{p}=n!/(\left \lfloor n/p \right \rfloor !p^{\left \lfloor n/p \right \rfloor })\) 。
举个例子:\((7!)_{3}=1·2·\underbrace{1}_{1*3} ·4·5·\underbrace{2}_{2*3}·7 \equiv 2 \ (mod \ 3)\) 。
然后我们可以发现一个每次需要计算的是 \((\left \lfloor \frac{n}{p} \right \rfloor !)_{p}+fac[n\%p]\) ,一直递归到 \(n \le 1\) 时就得到答案了,如果我们预处理下 \(fac[p-1]\),那么我们就能做到 \(O(log_{p}n)\) 的时间复习度。
struct Fact{
int N;
vector<i64> fac;
Fact() {}
Fact(int N_, i64 p = 1e9 + 7) : fac(N_ + 1) {
N = N_;
fac[0] = 1;
for (i64 i = 1; i < p; i++) fac[i] = fac[i - 1] * i % p;
}
inline i64 get_fact(i64 n, i64 p) {
i64 res = 1;
while (n > 1) {
if ((n / p) % 2) res = p - res;
res = res * fac[n % p] % p;
n /= p;
}
return res;
}
};
二、\(Legendre\) 定理:时间复杂度为 \(log_{p}n\)
1、用途:可以求出某个模数 \(p\) 在 \(n!\) 中所出现的幂次数。
2、我们令 \(v_p(n!)\) 表示 \(n!\) 的阶乘的所有素因子分解中 \(p\) 出现的次数,很明显我们能根据容斥得到如下式子,即 \(v_p(n!)=\sum_{i=1}^{p_i \le n}\left \lfloor \frac{n}{p_i} \right \rfloor=\frac{n-S_{p}(n)}{p-1}\) 。
3、其中 \(S_{p}(n)\) 表示 \(n\) 为 \(p\) 进制下 \(n\) 的各个数位的和。
4、特别的当 \(p=2\) 时,式子为 \(v_{2}(n!)=n-S_{2}(n)\) 。
struct Legedre{
inline i64 multi_fact(i64 n, i64 p) {
i64 cnt = 0;
do {
n /= p;
cnt += n;
} while (n);
return cnt;
}
inline i64 multi_fact2(i64 n, i64 p) {
i64 cnt = 0;
i64 m = n;
while (n) {
cnt += n % p;
n /= p;
}
return (m - cnt) / (p - 1);
}
};
三、\(Kummer\) 定理:时间复杂度为 \(log_{p}n\)
1、用途:可以求出某个模数 \(p\) 在组合数 \(C_{n}^{m}\) 中出现的幂次数,公式为:\(v_p(C_{n}^{m})=\frac{S_p(m)+S_{p}(n-m)-S_{p}(n)}{p-1}\) 。
struct Kummer{
inline i64 multi_fact2(i64 n, i64 m, i64 p) {
i64 cnt1 = 0, cnt2 = 0, cnt3 = 0;
i64 k = n - m;
while (n) {
cnt1 += n % p;
n /= p;
}
while (m) {
cnt2 += m % p;
m /= p;
}
while (k) {
cnt3 += k % p;
k /= p;
}
return (cnt2 + cnt3 - cnt1) / (p - 1);
}
};

浙公网安备 33010602011771号