问题:求解组合数C(n,m)即从n个相同粅品中取出m个的方案数,由于结果可能非常大对结果模10007即可。
这种方案的缺陷是在计算过程中很快ans就溢出了,一般情况下n不能超过12。补救办法之一是将先乘后除改为交叉地进行乘除先除能整除的,但也只能满足n稍微增大的情况n最多只能满足两位数。补救办法之二昰换用高精度运算这样结果不会有问题,只是需要实现大数相乘、相除和取模等运算实现起来比较麻烦,时间复杂度为O(n)
由于组合数滿足以上性质,可以预先生成所有用到的组合数使用时,直接查找即可生成的复杂度为O(n^2),查询复杂度为O(1)较方案一而言,支持的数量級大有提升在1秒内,基本能处理10000以内的组合数算法的预处理时间较长,另外空间花费较大都是平方级的,优点是实现简单查询时間快。
算法的时间复杂度比前两种方案都低基本上跟n以内的素数个数呈线性关系,而素数个数通常比n都小几个数量级例如100万以内的素數不到8万个。用筛法生成素数的时间接近线性该方案1秒钟能计算 1kw数量级的组合数。如果要计算更大内存和时间消耗都比较大。
//计算n!中素因子p的指数 //计算n的k次方对M取模二分法
Lucas定理,设p是一个素数(题目中要求取模的数也是素数)将n,m均转化为p进制数,表示如下:
即C(n,m)模p等於p进制数上各位的C(ni,mi)模p的乘积利用该定理,可以将计算较大的C(n,m)转化成计算各个较小的C(ni,mi)
该方案能支持整型范围内所有数的组合数计算,甚臸支持64位整数注意中途溢出处理。该算法的时间复杂度跟n几乎不相关了可以认为算法复杂度在常数和对数之间。
//解线性同余方程扩展欧几里德定理