如何计算(n!)%1000000009
How to calculate (n!)%1000000009
我需要找到n!%1000000009。在1到20的范围内,N的类型是2^k。我使用的函数是:
#define llu unsigned long long
#define MOD 1000000009
llu mulmod(llu a,llu b) // This function calculates (a*b)%MOD caring about overflows
{
llu x=0,y=a%MOD;
while(b > 0)
{
if(b%2 == 1)
{
x = (x+y)%MOD;
}
y = (y*2)%MOD;
b /= 2;
}
return (x%MOD);
}
llu fun(int n) // This function returns answer to my query ie. n!%MOD
{
llu ans=1;
for(int j=1; j<=n; j++)
{
ans=mulmod(ans,j);
}
return ans;
}
我的需求是这样的,我需要调用函数'fun' n/2次。我的代码运行太慢,k值在15左右。有更快的方法吗?
编辑:我在实际计算2 *((张)C (2 ^ (k - 1) 1)) * (((2 ^ (k - 1)) !) ^ 2]我的范围2 ^ 2 ^ k (k - 1)。我的程序要求(nCr)%MOD关心溢出。
编辑:我需要一个有效的方法来找到nCr%MOD的大n。
mulmod
例程可以大大提高k的速度。
1)'%'是多余的,因为(a + b)都小于n。
-评估c = a+b; if (c>=N) c-=N;
就足够了2)可同时处理多个比特;参见"俄罗斯农民算法"的优化
3) a * b
实际上足够小,适合64位unsigned long long,没有溢出
由于实际问题是关于nCr mod M,因此高级优化需要使用递归式
(n+1)Cr mod M = (n+1)nCr / (n+1-r) mod M.
由于公式((nCr) mod M)*(n+1)不能被(n+1-r)整除,因此除法需要通过与模逆(n+r-1)^(-1)的乘法来实现。模逆b^(-1)是b^(M-1),因为M是素数。(否则就 b ^(φ ()),在φ是欧拉Totient函数。)
模幂运算通常是通过重复平方来实现的,在这种情况下,每个除数需要进行约45次模乘法。
如果你可以使用递归式
nC(r+1) mod M = nCr * (n-r) / (r+1) mod M
只需要计算(r+1)^(M-1) mod M一次
既然您正在为n
的多个顺序值寻找nCr
,您可以使用以下命令:
(n+1)Cr = (n+1)! / ((r!)*(n+1-r)!)
(n+1)Cr = n!*(n+1) / ((r!)*(n-r)!*(n+1-r))
(n+1)Cr = n! / ((r!)*(n-r)!) * (n+1)/(n+1-r)
(n+1)Cr = nCr * (n+1)/(n+1-r)
这样可以避免为每个i
显式调用阶乘函数。
此外,要保存对nCr的第一次调用,可以使用:
nC(n-1) = n //where n in your case is 2^(k-1).
编辑:
正如Aki Suihkonen所指出的,(a/b) % m != a%m / b%m
。所以上面的方法。上面的方法不能一开箱即用。有两种不同的解决方案:
1000000009
是素数,这意味着a/b % m == a*c % m
,其中c
是b
的倒数模m
。你可以在这里找到如何计算它的解释,并点击Extended Euclidean Algorithm
的链接了解更多关于如何计算它的信息。另一个可能更容易的选择是认识到,由于EDIT根据评论,我不相信这种方法会起作用nCr * (n+1)/(n+1-r)
必须给出一个整数,因此必须可以将n+1-r == a*b
写入a | nCr
和b | n+1
(这里的|
意味着除法,如果您喜欢,您可以将其重写为nCr % a == 0
)。在不失一般性的前提下,先设a = gcd(n+1-r,nCr)
,再设b = (n+1-r) / a
。这给出了(n+1)Cr == (nCr / a) * ((n+1) / b) % MOD
。现在你的除法保证是准确的,所以你只需要计算它们,然后像以前一样进行乘法运算。
另一个我可能会尝试的是在你的llu mulmod(llu a,llu b)
llu mulmod(llu a,llu b)
{
llu q = a * b;
if(q < a || q < b) // Overflow!
{
llu x=0,y=a%MOD;
while(b > 0)
{
if(b%2 == 1)
{
x = (x+y)%MOD;
}
y = (y*2)%MOD;
b /= 2;
}
return (x%MOD);
}
else
{
return q % MOD;
}
}
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 递归函数计算序列中的平方和(并输出过程)
- (C++)分析树以计算返回错误值的简单算术表达式
- 我的字符计数代码计算错误.为什么
- 在计算中使用二的幂有多有利可图
- 如何计算文件中的"columns"数?
- 计算排序向量的向量中唯一值的计数
- 如何使用 std::累积在 C++ 中计算总和立方体
- 使用Qt C++计算类似Git的SHA1哈希
- OpenCV C++.快速计算混淆矩阵
- cpp二进制搜索问题,计算给定数组中输入元素的出现次数
- C++如何计算用户输入的数字中的偶数位数
- 如何计算数据类型的范围,例如int
- 类似枚举的计算常量
- 计算每个节点的树高,帮助我解释这个代码解决方案
- 多个If语句与使用逻辑运算符计算条件的单个语句的比较
- 计算缩放多边形的比例,得到给定的多边形面积
- 在C++中如何在没有pow的情况下进行基础计算
- 计算平均值,不包括上次得分
- 如何计算(n!)%1000000009