![d289974af0badd680d66eadfaf85dfc0.png](https://img-blog.csdnimg.cn/img_convert/d289974af0badd680d66eadfaf85dfc0.png)
卢卡斯定理是一个与组合数有关的数论定理,在算法竞赛中用于求组合数对某质数的模。在我们谈论卢卡斯定理前,我们先来看看朴素的求组合数的方法有哪些。
如果直接根据定义
所以只需要用
然而,实际上,组合数的增长速度是非常快的,
所幸算法竞赛中的题目常常会要求将结果对某个质数
模
绕了一圈,怎么还没提到卢卡斯定理呢?嗯……一般来说,这个方法够用了。偏偏,有时候,
这下麻烦了。如果
卢卡斯定理(Lucas's theorem):
对于非负整数和质数
,
,其中
、
是
和
的
进制展开。
但其实,我们一般使用的是这个可以与之互推的式子:
当
就像辗转相除法那样,可以利用这个式子递归求解,递归出口是
// 需要先预处理出fact[],即阶乘
inline ll C(ll m, ll n, ll p)
{
return m < n ? 0 : fact[m] * inv(fact[n], p) % p * inv(fact[m - n], p) % p;
}
inline ll lucas(ll m, ll n, ll p)
{
return n == 0 ? 1 % p : lucas(m / p, n / p, p) * C(m % p, n % p, p) % p;
}
网上说卢卡斯定理的复杂度是
C()
函数应该都是
接下来我们来证明这个式子。如果你对数学推导没有兴趣可以走了(
设
由于
显然等号右边是
我们有二项式定理:
现在我们设
再由二项式定理有
注意在这个和式中,
Pecco:算法学习笔记(目录)zhuanlan.zhihu.com