\binom{n}{m}\bmod p = \binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\binom{n\bmod p}{m\bmod p}\bmod p
观察上述表达式,可知 n\bmod p 和 m\bmod p 一定是小于 p 的数,可以直接求解,\displaystyle\binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor} 可以继续用 Lucas 定理求解。这也就要求 p 的范围不能够太大,一般在 10^5 左右。边界条件:当 m=0 的时候,返回 1。
考虑 \displaystyle\binom{p}{n} \bmod p 的取值,注意到 \displaystyle\binom{p}{n} = \frac{p!}{n!(p-n)!},分子的质因子分解中 p 次项恰为 1,因此只有当 n = 0 或 n = p 的时候 n!(p-n)! 的质因子分解中含有 p,因此 \displaystyle\binom{p}{n} \bmod p = [n = 0 \vee n = p]。进而我们可以得出
注意前者只有在 p 的倍数位置才有取值,而后者最高次项为 n\bmod p \le p-1,因此这两部分的卷积在任何一个位置只有最多一种方式贡献取值,即在前者部分取 p 的倍数次项,后者部分取剩余项,即 \displaystyle\binom{n}{m}\bmod p = \binom{\left\lfloor n/p \right\rfloor}{\left\lfloor m/p\right\rfloor}\cdot\binom{n\bmod p}{m\bmod p}\bmod p。
证明:我们知道在模奇素数 p 意义下,1,2,\dots ,p-1 都存在逆元且唯一,那么只需要将一个数与其逆元配对发现其乘积均为(同余意义下)1,但前提是这个数的逆元不等于自身。那么很显然 (p-1)!\bmod p 就是逆元等于其自身的数的乘积,这两个数为 \pm 1。在 p 为 2 时单独讨论即可。
对于整数 n,令 (n!)_p 表示所有小于等于 n 但不能被 p 整除的正整数的乘积,即 (n!)_p=n!/(\lfloor n/p\rfloor !p^{\lfloor n/p\rfloor})。
Wilson 定理指出 (p!)_p=(p-1)!\equiv -1\pmod p 且可被推广至模素数 p 的幂次。
递归的结果,三个部分中,左边部分随着递归结束而自然消失,中间部分可以利用 Wilson 定理的推论 0,右边部分就是推论 2 中的 \prod_{j\geq 0}(N_j!)_p。
下面这种写法,拥有单次询问 O(plogp) 的时间复杂度。其中 int inverse(int x) 函数返回 x 在模 p 意义下的逆元。
代码实现
LL calc(LL n, LL x, LL P) {
if (!n) return 1;
LL s = 1;
for (LL i = 1; i <= P; i++)
if (i % x) s = s * i % P;
s = Pow(s, n / P, P);
for (LL i = n / P * P + 1; i <= n; i++)
if (i % x) s = i % P * s % P;
return s * calc(n / x, x, P) % P;
}
LL multilucas(LL m, LL n, LL x, LL P) {
int cnt = 0;
for (LL i = m; i; i /= x) cnt += i / x;
for (LL i = n; i; i /= x) cnt -= i / x;
for (LL i = m - n; i; i /= x) cnt -= i / x;
return Pow(x, cnt, P) % P * calc(m, x, P) % P * inverse(calc(n, x, P), P) %
P * inverse(calc(m - n, x, P), P) % P;
}
LL exlucas(LL m, LL n, LL P) {
int cnt = 0;
LL p[20], a[20];
for (LL i = 2; i * i <= P; i++) {
if (P % i == 0) {
p[++cnt] = 1;
while (P % i == 0) p[cnt] = p[cnt] * i, P /= i;
a[cnt] = multilucas(m, n, i, p[cnt]);
}
}
if (P > 1) p[++cnt] = P, a[cnt] = multilucas(m, n, P, P);
return CRT(cnt, a, p);
}
若不考虑 excrt 的复杂度,通过预处理 \frac{n!}{n以内的p的所有倍数的乘积}\bmod{p}以内的的所有倍数的乘积,可以使时间复杂度优化至单次 O(p + logp)。而如果 p 是固定的,我们在一开始就可以对 p 进行分解,并进行预处理,可以达到总复杂度 O(p + Tlogp)。
buildLast update and/or translate time of this article,Check the history editFound smelly bugs? Translation outdated? Wanna contribute with us? Edit this Page on Github peopleContributor of this article OI-wiki translateTranslator of this article Visit the original article! copyrightThe article is available under CC BY-SA 4.0 & SATA ; additional terms may apply.