Lucas定理用于计算组合数取模$C_n^x\bmod p$,适用于$n$很大而$p$较小的情况。
Lucas定理
若要计算$C_n^m\bmod p$,其中$p$是素数。
Lucas定理
令$n=ap+b,m=cp+d$。
故:
对于$C_b^d$,范围在$p$以内,可以通过阶乘算出来。
对于$C_a^c$,利用Lucas定理递归计算。
1 | LL Quick_Pow(LL a,LL b) { |
证明
Lucas定理我也不会证,贴个大佬的博客。
时间复杂度
若忽略阶乘(对阶乘进行预处理)与求逆元的时间(线性求逆元),那么一次计算的时间复杂度为$O(\log_pn)$。
扩展Lucas定理
Lucas定理只能用于求解组合数模素数,若$p$是一个非素数怎么办呢?
当$p=p_1^1\cdot p_2^1\cdots p_k^1$时,可以直接使用CRT合并。
但当$p=p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k}$时,不能直接使用CRT合并,此时就需要用到扩展Lucas定理。
扩展Lucas定理
首先对分解后的$p$写出$k$个同余方程:
若能够求出$b_i$,就可以使用CRT合并了。
因此现在考虑如何求出$x\bmod p_i^{a_i}$。
将组合数写成阶乘形式:
接下来我们考虑将$x!$进行拆分,下面我们用$16!\bmod 3^2$举例。
将$x!$的所有$p_i$的倍数单独拿出,提取公因数得到三部分:
- 第三部分,$1\times2\times3\times4\times5$,发现是子问题$\frac n{p_i}!$,递归处理。
- 第一部分,$1\times2\times4\times5\times7\times8\times10\times11\times13\times14\times16$,这部分不含有$p_i$,分块计算,按照$p_i^{a_i}$分块,显然每块得到的答案相同,因此可以使用$O(p_i^{a_i})$的时间暴力计算,然后使用快速幂得到所有答案。
- 第二部分,$3^5$,暂时无视,等会儿再说。
- 当我们完成上述过程后,我们就求出了$x!$中所有除开$p_i$的数的乘积,记为$f(x)$,这个乘积与$p_i^{a_i}$互素,故一定存在逆元,可以使用$\frac{f(n)}{f(m)f(n-m)}$计算出$C_n^m\bmod p_i^{a_i}$的一部分。
- 对于$C_n^m\bmod p_i^{a_i}$的另一部分,也就是我们在计算$x!$中被无视的所有$p_i$,记其个数为$g(x)$,显然我们可以在$O(\log x)$的时间内得到$g(x)$,那么$p^{g(n)-g(m)-g(n-m)}$就是剩下的部分。
将上述两部分乘起来即可得到$C_n^m\bmod p_i^{a_i}$。
1 | void Exgcd(LL a,LL b,LL &gcd,LL &x,LL &y) { |
时间复杂度
根据主定理可以得到$T(n)=O(p^a)$。