查找大 n 和 k 模 m 的二项式系数
Finding binomial coefficient for large n and k modulo m
我想使用以下约束来计算nCk mod m:
n<=10^18
k<=10^5
m=10^9+7
我读过这篇文章:
计算大 n 和 k 的二项式系数 (nCk(
但这里的 m 值是 1009。因此,使用卢卡斯定理,我们只需要计算 aCb 的 1009*1009 个不同值,其中 a,b<=1009
如何在上述约束下做到这一点。我无法在给定约束下制作 O(m*k( 空间复杂度数组。
帮助!
(n, k)
的双名义系数由下式计算:
(n, k) = n! / k! / (n - k)!
要使这适用于大量n
和k
模,m
观察到:
数模
m
的阶乘可以逐步计算,在每一步采取结果% m
。但是,当 n 到 10^18 时,这将太慢了。因此,有一些更快的方法,其中复杂性由模限制,您可以使用其中的一些。(a / b) mod m
的除数等于(a * b^-1) mod m
,其中b^-1
是b
模m
(即(b * b^-1 = 1) mod m
(的倒数。
这意味着:
(n, k) mod m = (n! * (k!)^-1 * ((n - k)!)^-1) mod m
使用扩展欧几里得算法可以有效地找到数字的倒数。假设您已经整理了因子计算,则算法的其余部分很简单,只需注意乘法时的整数溢出即可。这是最高可工作的参考代码 n=10^9
.为了处理更大的数字,阶乘计算应该被更有效的算法所取代,并且代码应该稍微调整以避免整数溢出,但主要思想将保持不变:
#define MOD 1000000007
// Extended Euclidean algorithm
int xGCD(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int x1, y1, gcd = xGCD(b, a % b, x1, y1);
x = y1;
y = x1 - (long long)(a / b) * y1;
return gcd;
}
// factorial of n modulo MOD
int modfact(int n) {
int result = 1;
while (n > 1) {
result = (long long)result * n % MOD;
n -= 1;
}
return result;
}
// multiply a and b modulo MOD
int modmult(int a, int b) {
return (long long)a * b % MOD;
}
// inverse of a modulo MOD
int inverse(int a) {
int x, y;
xGCD(a, MOD, x, y);
return x;
}
// binomial coefficient nCk modulo MOD
int bc(int n, int k)
{
return modmult(modmult(modfact(n), inverse(modfact(k))), inverse(modfact(n - k)));
}
只需使用以下事实
(n, k) = n! / k! / (n - k)! = n*(n-1)*...*(n-k+1)/[k*(k-1)*...*1]
所以你实际上只有2*k=2*10^5
因素。对于数字的倒数,您可以使用 kfx 的建议,因为您的m
是素数。
首先,您不需要预先计算和存储所有可能的aCb值! 它们可以按案例计算。
其次,对于 (k <m(> (n 选择 k( mod m
= ((n mod m( 选择 k( mod m
那么由于 (n mod m( <10^9+7,你可以简单地使用 @kfx 提出的代码。
我们要计算 nCk (mod p(。当 0 <= k <= p-2 时,我将处理,因为卢卡斯定理处理其余部分。
威尔逊定理指出,对于素数p,(p-1(!= -1(mod p(,或等价(p-2(!= 1(mod p((按除法(。
按部门: (k!^(-1( = (p-2(!/(k!( = (p-2((p-3(...(k+1((模组 p(
因此,二项式系数为 n!/(k!(n-k(!= n(n-1(...(n-k+1(/(k!( = n(n-1(...(n-k+1((P-2((P-3(...(k+1((模组 p(
瞧。您不必进行任何逆向计算或类似的事情。编码也相当容易。需要考虑的几个优化:(1(您可以替换(p-2((p-3(...与 (-2((-3(...;(2( nCk 是对称的,因为 nCk = nC(n-k( 所以选择需要你做较少计算的那一半。
- 正在查找文档以获得PS4平台的C++中的设备信息
- 在C++中查找文件
- 模板元程序查找相似的连续类型名称
- 在UNIX系统中使用DIR查找文件的字节大小
- 查找最接近的大于当前数字的数字的索引
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 查找后更改类变量
- 使用正则表达式regex_search在字符串中查找字符串
- 使用gcc从静态链接的文件中查找可选符号
- 在C++中查找范围的长度
- 算法问题:查找从堆栈中弹出的所有序列
- 在Windows中查找扬声器输出的当前音量级别
- 如何在C++中使用X509证书模在令牌中查找私钥
- 使用.find函数在c++中查找字符和另一个字符之间的大小
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 在 for 循环中查找问题时遇到困难
- 如何在文件中查找字节序列
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 使用堆查找第K个最大元素的时间复杂性
- 查找大 n 和 k 模 m 的二项式系数