Lucas定理解决的问题是组合数取模。数学上来说,就是求:
这里(n,m)可能很大,比如达到(10^{15}),而(p)在(10^9)以内。显然运用常规的阶乘方法无法直接求解,所以引入Lucas定理。
Lucas定理
把(n)和(m)写成(p)进制数的样子(如果长度不一样把短的补成长的那个的长度):
那么:
证明
如果把Lucas定理从递归的角度理解,它其实是这样的:
这个定理的一个很巧妙的证法是通过二项式定理来说明上面的式子是成立的。
首先,对于任意质数(p),有:
证明可以由费马小定理直接得出:
(当然同样也有((a+b)^pequiv a^p+b^pmod p))
利用这个性质,我们证明Lucas定理:
考察等式左右两边(x^m)的系数,可以发现:
所以上面的式子成立,证明完毕。
算法时间复杂度为(O(lop_pn)),如果不算预处理什么的。如果能够支持预处理,那么就加一个(O(p)),要不就用快速幂,乘上(O(logp))。
拓展
求解(p)不是质数的情况。
一个很简单的做法就是把(p)分解成多个不同素数的幂相乘,由于是多个不同素数的幂,所以可以直接运用中国剩余定理将答案合并。所以现在问题就转化成,(p)为素数,求:
在这种情况下,使用阶乘的方法就好。
所以问题就变成了快速求(n!mod p^q)。
一个十分经典的例子是:(19!mod 3^2):
可以注意到,我们把(p)的倍数提取出来,并且把它们都提出一个(p),那么剩下的又变成了一个阶乘,可以递归计算。前面的部分是(p^q)以内循环的,即(1*2*4*5*7*8equiv10*11*13*14*16*17*19mod 3^2),所以只用算一个,快速幂一下即可。中间的那一项就直接在求组合数的时候相减即可。多出来的非循环的部分一定小于(p^q),所以暴力即可。求一个(n!mod p^q)的复杂度为(O(p^qlog_2n(log_pn-q)))。
所以拓展情况带上CRT的总复杂度为(O(p^qlog_2n(log_pn-q)+nlog_2p))。