优化模块化算法的代码

时间:2013-02-06 18:49:14

标签: c++ math optimization modular-arithmetic

我正在尝试计算大数字的下面的表达式。

N!/((N/2)!(N/2)!)

由于这个表达式的值会非常大,我只需要这个表达式的值为一些素数。假设此表达式的值为x,我选择素数1000000007;我正在寻找x % 1000000007

这是我的代码。

#include<iostream>
#define MOD 1000000007
using namespace std;
int main()
{
    unsigned long long A[1001];
    A[2]=2;
    for(int i=4;i<=1000;i+=2)
    {
        A[i]=((4*A[i-2])/i)%MOD;
        A[i]=(A[i]*(i-1))%MOD;

    while(1)
    {
        int N;
        cin>>N;
        cout<<A[N];
    }
}

但即使这么多的优化也没有大的N值。例如,如果N是50,正确的输出是605552882,但这给了我132924730。如何进一步优化以获得正确的输出?

注意:我只考虑N为偶数。

2 个答案:

答案 0 :(得分:6)

进行模运算时,不存在除法等操作。相反,你采用分母的模逆,并乘以。使用由Etienne Bezout于1779年发现的扩展欧几里德算法计算模逆:

# return y such that x * y == 1 (mod m)
function inverse(x, m)
    a, b, u := 0, m, 1
    while x > 0
        q, r := divide(b, x)
        x, a, b, u := b % x, u, x, a - q * u
    if b == 1 return a % m
    error "must be coprime"

divide函数返回商和余数。上面给出的所有赋值运算符都是同时赋值,其中首先计算所有右侧,然后同时分配所有左侧。您可以在my blog看到有关模块化算术的更多信息。

答案 1 :(得分:1)

  1. 首先,根本不需要模数除法,您的公式可以按如下方式重新编写:

    N!/((N / 2)!^ 2) =(1.2.3 ... N)/((1.2.3 ... N / 2)*(1.2.3 ... N / 2)) =((N / 2 + 1)... N)/(1.2.3 ... N / 2))

    • 好的,现在你将较大的数字除以较小的
    • 所以你可以通过乘以除数和divident
    • 来迭代结果
    • 所以booth子结果具有相似的幅度
    • 任何时候这两个数字都可以整除2向左移动
    • 这将确保不会溢出
    • 如果你在和(N / 2)!而不是仅为其余部分继续多重化。
    • 任何时候这两个子结果都可被任何分割
    • 整除
    • 直到你留下了1个
    • 的divison
    • 在此之后,您可以使用模数算法,直到最后正常。
  2. 更高级的方法请看这个。

    • N!和(N / 2)!比第一次看起来更加可分解
    • 我已经解决了一段时间了......
    • 这是我发现的:Fast exact bigint factorial
    • 快捷方式你的条件N!和((N / 2)!)^ 2将完全消失。
    • 仅简单的主要分解+ 4N&lt; - &gt; 1N更正将提醒
  3. 溶液:

    I. (4N!)=((2N!)^2) . mul(i=all primes<=4N) of [i^sum(j=1,2,3,4,5,...4N>=i^j) of [(4N/(i^j))%2]]
    II. (4N)!/((4N/2)!^2) = (4N)!/((2N)!^2)
    ----------------------------------------
    I.=II. (4N)!/((2N)!^2)=mul(i=all primes<=4N) of [i^sum(j=1,2,3,4,5,...4N>=i^j) of [(4N/(i^j))%2]]
    
    • 唯一的问题是N必须能被4整除...所以所有术语都是4N。
    • 如果你有N%4!= 0而不是解决N-N%4而且结果是错误的1-3号码。

    希望有所帮助

相关问题