赤裸裸的组合数取模没什么意思,但也是必须掌握的一门知识。一个计数的问题辛辛苦苦搞到最后发现被取模坑成狗也是很有可能的。今天主要总结一下各类取模问题。限长整(long)范围内。 所谓组合数取模,即求 Cmn % p
1<=m<=n<=1e3,1<=p<=long 杨辉三角,直接递推 Cmn=Cmn−1+Cm−1n−1
-
1<=m<=n<=1e6,1<=p<=long,n<p,p∈primes
直接逆元,预处理出 n! 及其逆元即可。由费马小定理,对于 (a,p)=1 ,则, a−1=ap−2
-
1<=m<=n<=long,1<=p<=long,p∈primes
Lucas定理。即令
n=n0+n1p+n2p2+⋯+nkpk,0<=ni<p
m=m0+m1p+m2p2+⋯+mkpk,0<=mi<p
则有:
Cmnmodp=∏i=0kCminimodp
若存在 ni<mi ,则 Cmnmodp=0
-
1<=m<=n<=1e6,1<=p<=long
没错,将 Cmn 质因数分解,然后求模。具体是
- 分别将 n!,m!,(n−m)! 分解掉,然后指数相减得到最终的质因数分解。
- 对每个质因数,快速幂取模
-
1<=m<=n<=long,1<=p<=1e6
由于p可以是合数,所以前面无论逆元还是Lucas都解决不了。
将前面几种方法结合一下。- 将p质因数分解 p=∏ki=0paii
- 对于每个 i∈[0,k] ,求 Cmnmodpaii=ri
- 利用CRT求得最终模数
于是问题变为,如何求 Cmnmodpa ?
考虑 n!=qpk,(q,p)=1 , k 称作p 在 n! 中的重数。
对 m! 和 (n−m)! 做同样处理,则
Cmnmodpa=qnq−1mq−1n−mpkn−km−kn−mmodpa
k 可以用O(logk(n)) 求出来。若能求出 q 问题就迎刃而解了。
不妨令
f(n)=∏p∤dndmodp
我们将 [1,n] 分成两类:
1...p−1,p+1....2p−1,...,sp+1...n
p,2p,3p,4p,...,sp
第一类以 pa 为循环节,可利用 O(pa) 的复杂度求出,记答案为 g(n)
第二类,容易发现其实就是 f(s)
得到 f(n)=g(n)f(np)
-
总结:
其实只要 (n!,p)=1 ,根据裴蜀定理,这意味着 n!∗x+b∗p=1 有解。对于 1<=i<=n ,均存在关于 p 的i−1 ,这时候可以用逆元在 O(nlog(p)) 的时间出解。
总的来说,将取模问题归结为两类:n
-
1<=m<=n<=1e6,1<=p<=long,n<p,p∈primes