【学习笔记】扩展Lucas定理

0.概述

用于解决组合数取模的问题。请先学习中国剩余定理,有点作用的。

1.分解

现在我们要求 (nm)modp{n\choose m}\bmod p 的结果,pp 是个小家伙,n,mn,m 长的很魁梧。

现在我们找到 pp 的质因数分解 p=ipitip=\prod_{i}p_i^{t_i}

我们如果能求出 (nm)modpiti{n\choose m}\bmod p_i^{t_i}

再用中国剩余定理合成回去即可了!所以下文就只讨论对 pk(pP)p^k(p\in\Bbb{P}) 取模的情况。

2.硬算

(nm)=n!m!(nm)!{n\choose m}=\frac{n!}{m!(n-m)!}

我们试着单独考虑 n!,m!,(nm)!n!,m!,(n-m)!pp 的倍数,就可以求逆元了。用 f(n)=npxmodpkf(n)=\frac{n}{p^x}\bmod p^k 来表示,其中 xx 是满足 pxnp^x|n 最大的 xx

我们将 n!n! 分成两部分,一部分是 pp 的倍数,另一部分不是。即 n!=i=1np(ip)i=1,¬(pi)nin!=\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}(ip)\cdot \prod_{i=1,\neg(p|i)}^{n}i

后面那一部分大有搞头。毕竟你要对 pkp^k 取模,做乘法之前也可以先行取模。我们根据“除以 pkp^k 的商”进行分类,就可以看出 i=1,¬(pi)ni(i=1,¬(pi)pki)npki=pknpk+1,¬(pi)ni(modpk)\prod_{i=1,\neg(p|i)}^{n}i\equiv\left(\prod_{i=1,\neg(p|i)}^{p^k}i\right)^{\lfloor\frac{n}{p^k}\rfloor}\cdot\prod_{i=p^k\lfloor\frac{n}{p^k}\rfloor+1,\neg(p|i)}^{n}i\pmod{p^k}

然后前面那一坨把 pp 提出来,得到 i=1np(ip)=pnpi=1npi=np!pnp\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}(ip)=p^{\lfloor\frac{n}{p}\rfloor}\prod_{i=1}^{\lfloor\frac{n}{p}\rfloor}i=\left\lfloor\frac{n}{p}\right\rfloor\large{!}\cdot p^{\lfloor\frac{n}{p}\rfloor}

注意到 np!\lfloor\frac{n}{p}\rfloor! 中可能仍然有 pp 的因数,于是要递归处理。总结一下就是

f(n)f(np)(i=1,¬(pi)pki)npki=pknpk+1,¬(pi)ni(modpk)f(n)\equiv f\left(\middle\lfloor\frac{n}{p}\middle\rfloor\right)\cdot\left(\prod_{i=1,\neg(p|i)}^{p^k}i\right)^{\lfloor\frac{n}{p^k}\rfloor}\cdot\prod_{i=p^k\lfloor\frac{n}{p^k}\rfloor+1,\neg(p|i)}^{n}i\pmod{p^k}

复杂度呢?很明显是递推式 T(n)=T(np)+O(pk+logn)T(n)=T(\lfloor\frac{n}{p}\rfloor)+\mathcal O(p^k+\log n) 。不妨认为 logn\log n 是个小于 pkp^k 的值,就有总复杂度 T(n)=O(pklogn)T(n)=\mathcal O(p^k\log n)

显然,最坏的情况是 O(plogn)\mathcal O(p \log n) 的。中国剩余定理合并的时间是不用考虑的,很小。

pp 的因数提了出来,pp 的指数是几呢?众所周知,maxxZ+,pxnx=i=1+npi\max_{x\in\Z^+,p^x|n}x=\sum_{i=1}^{+\infty}\left\lfloor\frac{n}{p^i}\right\rfloor

然后就完了。可以提一下 k=1k=1 的特殊情况,(nm)(n/pm/p)(nmodpmmodp)(modp),pP{n\choose m}\equiv{n/p\choose m/p}{n\bmod p\choose m\bmod p}\pmod{p},\quad p\in\Bbb{P}

除法是下取整,P\Bbb P 是质数集合。

代码

不想写,今天爆零了,ZzZzSySyXjhXjhZxyZxy 等大佬各种 AKAK 虐全场。

想看他们的博客,还用南无炼铜佛的博客做引子。

while(true) cout << "我好菜啊啊啊啊!" << endl;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章