Part 0. 引子
众所周知:
Cmn=m!(n−m)!n!现在有个问题:
- 当 n,m 比较大的时候,直接用除法会寄掉(因为
long long
能够存储的数相对于阶乘而言小得可怜),此时一般会让你求出这个组合数对一个数取模的结果。但是除法不能直接取模,怎么办?
这个问题的答案还是比较显然的,我们只要用费马小定理求出阶乘的逆元。
然后第二个问题来了:
- 有多组测试数据,每组的取模都不一样,每一次都要求一个很大的组合数,怎么办?
对于这个问题,有一个非常简单的办法:想办法给出题人打 100 万,然后要到数据。
还有一个办法:
Part 1. Lucas 定理的证明
对于一个组合数:
Cpnmodp(p为素数,n≤p)可以把它表示成这样的形式:
i!(p−i)!p!modp由于 p 是质数注意到分子(p!)的质因数分解中只有一个 p,当 i∈[1,p−1] 的时候,分母中没有因数 p,所以取模的结果就是 0。当 i∈{0,p} 的时候,显然组合数等于 1,因此有:
Cpnmodp=[n∈{0,p}]那么再结合二项式定理的模数,即:
(a+b)pmodp=k=0∑nCnkakbp−kmodp=k=0∑n(Cnkakbp−kmodp)modp=k=0∑n[(Cnkmodp)akbp−k]modp=k=0∑n([k∈{0,n}]akbp−k)modp=(ap+bp)modp注意到刚才的推导由于不需要保证互质等条件,适用于 a,b 为多项式的情况。
那么我们就带进去个式子试试?
设 f(x)=axn+bxm,则:
fp(x)modp=(axn+bxm)pmodp=(axn+bxm)pmodp=(apxnp+bpxmp)modp=(axnp+bxmp)modp(费马小定理)=f(xp)到这里,我们距离推导 Lucas 定理又近了 0 米,继续加油!
上面这一坨东西怎么和求一个组合数扯上关系呢?答案是:二项式定理可以提供组合数。
也就是这样:
(1+x)n=k=0∑nCnixi而我们要对这个式子取模:
(1+x)n=(1+x)p×⌊pn⌋(1+x)nmodp≡(1+xp)⌊pn⌋(1+x)nmodp这一坨东西可以分成前后两部分。第一部分的展开式