如何有效地使用Modulo?

时间:2015-11-14 23:43:55

标签: c performance store division modulo

我正在为自己做一个非常复杂的任务,在给定n个段时,我必须计算最大可能的序列数。

我发现加泰罗尼亚数字代表了这个序列,我让它适用于n <= 32。我得到的结果应该计算为1.000.000.007。我遇到的问题是“q”和“p”对于一个很长的int而言变得很大而且我在分割“q”和“p”之前不能只修改1.000.000.007,因为我会得到不同的结果。

我的问题是,是否有一种非常有效的方法来解决我的问题,或者我是否必须考虑以不同的方式存储值? 我的限制如下: - 仅限stdio.h / iostream - 只有整数 - n <= 20.000.000 - n> = = 2

#include <stdio.h>

long long cat(long long  l, long long  m, long long  n);

int main(){
    long long  n = 0;
    long long  val;
    scanf("%lld", &n);

    val = cat(1, 1, n / 2);

    printf("%lld", (val));

    return 0;
}

long long  cat(long long  q, long long  p, long long  n){
    if (n == 0) {
        return (q / p) % 1000000007;
    }
    else {
        q *= 4 * n - 2;
    }

    p *= (n + 1);

    return cat(q, p, n - 1);
}

2 个答案:

答案 0 :(得分:4)

为了有效地解决这个问题,你需要使用modular arithmeticmodular inverses代替除法。

在没有溢出的情况下证明(a * b) % c == ((a % c) * b) % c很简单。如果我们只是乘以,我们可以在每一步取结果mod 1000000007并始终保持在64位整数的范围内。问题在于分裂。 (a / b) % c不一定等于((a % c) / b) % c

为了解决除法问题,我们使用模块化逆。对于具有a素数和c的整数ca % c != 0,我们总能找到b整数a * b % c == 1。这意味着我们可以使用乘法作为除法。对于da可整除的任何整数(d * b) % c == (d / a) % c。这意味着((d % c) * b) % c == (d / a) % c,因此我们可以减少中间结果mod c而不会破坏我们的分裂能力。

我们想要计算的数字是(x1 * x2 * x3 * ...) / (y1 * y2 * y3 * ...) % 1000000007形式。我们可以改为计算x = x1 % 1000000007 * x2 % 1000000007 * x3 % 1000000007 ...y = y1 % 1000000007 * y2 % 1000000007 * y3 % 1000000007 ...,然后使用extended Euclidean algorithm计算z的模块逆y并返回(x * z) % 1000000007

答案 1 :(得分:2)

如果您正在使用gcc或clang和64位目标,则存在__int128 type。这为您提供了额外的位,但显然只有一点。

最有可能解决此类问题的最简单方法是使用&#34; bignum&#34;库,即处理任意大数字表示和算术运算的库。可以说是最受欢迎的开源示例是libgmp - 您应该能够轻松地使用该算法。它还调整了高性能标准。

显然,你可以自己重新实现这一点,将你的数字表示为例如一定大小的整数数组。您必须实现用于执行基本算术的算法,例如+, - ,*,/,%。如果你想做一个很好的学习体验,但是如果你只想专注于你想要实现的算法,那么使用libgmp并不羞耻。