如何计算{1,2,3,..........,n}的最小公倍数?

时间:2015-05-30 06:33:44

标签: math greatest-common-divisor lcm

如何找到 {1,2,...,n} LCM ,其中 0 < n < 10001 以最快的方式。一种方法是计算 n! / gcd(1,2,.....,n)但这可能很慢,因为 testcases 的数量是 t< 501 输出应为 LCM(n!)%1000000007

代码同样是:

#include<bits/stdc++.h>
using namespace std;
#define p 1000000007;
int fact[10001] = {1};
int gcd[10001] = {1};

int main()
{
    int i, j;
    for( i = 2;i < 10001; i++){
        fact[i] = ( i * fact[i-1]) % p;
    }
    for(i=2 ;i < 10001; i++){
        gcd[i] =__gcd( gcd[i-1], i );
    }

    int t;
    cin >> t;

    while( t-- ) {
        int n;
        cin >> n;
        int res = ( fact[n] / gcd[n] );
        cout << res << endl;
    }

    return 0;
}

但是这段代码表现不佳。为什么呢?

4 个答案:

答案 0 :(得分:4)

您当前的解决方案不正确,正如评论中所述。

解决这个问题的一种方法是认识到这些数字的最小公倍数只是小于或等于n的不同质数的所有“最大”幂的乘积。也就是说,找到每个素数p小于或等于n,然后找到每个素数的最大幂,使其仍然小于或等于n,然后乘以一起。对于给定的p,所述功率可以用伪代码表示为:

p ** math.Floor(math.Log(n) / math.Log(p))

这是Golang中一个立即返回的实现:

http://play.golang.org/p/8s4eE_CQ9Y

$ time go run lcm.go
5793339670287642968692270879166240098634860297998518825393138351148979300145773182308832598
<several lines later>
800000

real    0m0.225s
user    0m0.173s
sys     0m0.044s

为完整起见,此操场链接的完整代码将粘贴在此处:

package main

import (
    "fmt"
    "math"
    "math/big"
)

func main() {
    n := 10001

    primes := make([]int, 1, n)
    primes[0] = 2

SIEVE:
    for i := 3; i <= n; i++ {
        for _, p := range primes {
            if i%p == 0 {
                continue SIEVE
            }
        }
        primes = append(primes, i)
    }

    logN := math.Log(float64(n))
    lcm := big.NewInt(1)
    for _, p := range primes {
        floatP := float64(p)
        e := math.Floor(logN / math.Log(floatP))
        lcm.Mul(lcm, big.NewInt(int64(math.Pow(floatP, e))))
    }

    fmt.Println(lcm)
}

答案 1 :(得分:2)

我会以完全不同的方式计算:{1,...,n}的最小公倍数是所有素数p [i] <= n的乘积,每个素数都在幂底(log(n)/ log) (第[I]))。此产品可被所有数字整除,最多为n,这是最少的数字。你的主要麻烦是计算素数表。

答案 2 :(得分:0)

我会建议一些不那么动态的东西,但它会大大提高你的速度。设置一个阶乘表(可能是一个数组)并在那里存储预先计算的阶乘整数表示。这样,它是一个简单的O(1)操作,而不是O(n)。这是一个参考表,但您也可以自己预先计算:http://www.tsm-resources.com/alists/fact.html这样做是可以的,因为这些值永远不会改变。如果我们谈论速度优化,那么为什么不存储我们知道的值,而不是每次都计算它们呢?

但是,如果您反对预先存储这些计算,我建议您查看优化算法并从那里开始工作:

以下是两种用于更快的因子计算算法的优秀资源:

http://www.luschny.de/math/factorial/conclusions.html http://www.luschny.de/math/factorial/scala/FactorialScalaCsharp.htm

答案 3 :(得分:0)

这很简单,但似乎运行得足够快。可能阿米特库马尔古普塔的想法更快。在我的机器上堆栈溢出n = 9500,但可以通过记忆功能和从小数字到更大数字构建备忘录来修复。我没有采用模量,但修复很容易,特别是如果模数是素数。是吗?

import java.math.BigInteger;

public class LCM {

  // compute f(n) = lcm(1,...n)
  public static BigInteger f(int n) {
    if (n == 1) return BigInteger.ONE;
    BigInteger prev = f(n-1);
    return prev.divide(prev.gcd(BigInteger.valueOf(n)))
      .multiply(BigInteger.valueOf(n));
  }

  public static void main(String[] args) {
    int n = Integer.parseInt(args[0]);
    System.out.println("f(" + n + ") = " + f(n));
  }
}