0.概述
用于解决组合数取模的问题。请先学习中国剩余定理,有点作用的。
1.分解
现在我们要求 (mn)modp 的结果,p 是个小家伙,n,m 长的很魁梧。
现在我们找到 p 的质因数分解 p=i∏piti
我们如果能求出 (mn)modpiti
再用中国剩余定理合成回去即可了!所以下文就只讨论对 pk(p∈P) 取模的情况。
2.硬算
用 (mn)=m!(n−m)!n!
我们试着单独考虑 n!,m!,(n−m)! 中 p 的倍数,就可以求逆元了。用 f(n)=pxnmodpk 来表示,其中 x 是满足 px∣n 最大的 x 。
我们将 n! 分成两部分,一部分是 p 的倍数,另一部分不是。即 n!=i=1∏⌊pn⌋(ip)⋅i=1,¬(p∣i)∏ni
后面那一部分大有搞头。毕竟你要对 pk 取模,做乘法之前也可以先行取模。我们根据“除以 pk 的商”进行分类,就可以看出 i=1,¬(p∣i)∏ni≡⎝⎛i=1,¬(p∣i)∏pki⎠⎞⌊pkn⌋⋅i=pk⌊pkn⌋+1,¬(p∣i)∏ni(modpk)
然后前面那一坨把 p 提出来,得到 i=1∏⌊pn⌋(ip)=p⌊pn⌋i=1∏⌊pn⌋i=⌊pn⌋!⋅p⌊pn⌋
注意到 ⌊pn⌋! 中可能仍然有 p 的因数,于是要递归处理。总结一下就是
f(n)≡f(⌊pn⌋)⋅⎝⎛i=1,¬(p∣i)∏pki⎠⎞⌊pkn⌋⋅i=pk⌊pkn⌋+1,¬(p∣i)∏ni(modpk)
复杂度呢?很明显是递推式 T(n)=T(⌊pn⌋)+O(pk+logn) 。不妨认为 logn 是个小于 pk 的值,就有总复杂度 T(n)=O(pklogn)
显然,最坏的情况是 O(plogn) 的。中国剩余定理合并的时间是不用考虑的,很小。
把 p 的因数提了出来,p 的指数是几呢?众所周知,x∈Z+,px∣nmaxx=i=1∑+∞⌊pin⌋
然后就完了。可以提一下 k=1 的特殊情况,(mn)≡(m/pn/p)(mmodpnmodp)(modp),p∈P
除法是下取整,P 是质数集合。
代码
不想写,今天爆零了,Zz 和 Sy 和 Xjh 和 Zxy 等大佬各种 AK 虐全场。
想看他们的博客,还用南无炼铜佛的博客做引子。
while(true) cout << "我好菜啊啊啊啊!" << endl;