卢卡斯定理
引入
卢卡斯定理用于求解大组合数取模的问题,其中模数必须为素数。正常的组合数运算可以通过递推公式求解,但当问题规模很大,而模数是一个不大的质数的时候,就不能简单地通过递推求解来得到答案,需要用到卢卡斯定理。
定义
卢卡斯定理内容如下:对于质数 p,有
(nm)modp=(⌊n/p⌋⌊m/p⌋)⋅(nmodpmmodp)modp
观察上述表达式,可知 nmodp 和 mmodp 一定是小于 p 的数,可以直接求解,(⌊n/p⌋⌊m/p⌋) 可以继续用卢卡斯定理求解。这也就要求 p 的范围不能够太大,一般在 105 左右。边界条件:当 m=0 的时候,返回 1。
时间复杂度为 O(f(p)+g(n)logn),其中 f(n) 为预处理组合数的复杂度,g(n) 为单次求组合数的复杂度。
long long c(long long n, long long m, long long p){
if(m == 0) return 1;
else return (c(n % p, m % p, p) * c(n / p, m / p, p)) % p;
}
证明
考虑 (pn)modp 的取值,注意到 (pn)=p!n!(p−n)!,分子的质因子分解中 p 的次数恰好为 1,因此只有当 n=0 或 n=p 的时候 n!(p−n)! 的质因子分解中含有 p,因此 (pn)modp=[n=0∨n=p]。进而我们可以得出
(a+b)p=p∑n=0(pn)anbp−n≡p∑n=0[n=0∨n=p]anbp−n≡ap+bp(modp)(1)(2)(3)
注意过程中没有用到费马小定理,因此这一推导不仅适用于整数,亦适用于多项式。因此我们可以考虑二项式 fp(x)=(axn+bxm)pmodp 的结果
(axn+bxm)p≡apxpn+bpxpm≡axpn+bxpm≡f(xp)(4)(5)(6)
考虑二项式 (1+x)nmodp,那么 (nm) 就是求其在 xm 次项的取值。使用上述引理,我们可以得到
(1+x)n≡(1+x)p⌊n/p⌋(1+x)nmodp≡(1+xp)⌊n/p⌋(1+x)nmodp(7)(8)
注意前者只有在 p 的倍数位置才有取值,而后者最高次项为 nmodp≤p−1,因此这两部分的卷积在任何一个位置只有最多一种方式贡献取值,即在前者部分取 p 的倍数次项,后者部分取剩余项,即 (nm)modp=(⌊n/p⌋⌊m/p⌋)⋅(nmodpmmodp)modp。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】