有效地计算范围内整数的除数总数

时间:2012-02-06 22:54:27

标签: math prime-factoring

给定范围[1,200万],对于此范围内的每个数字,我需要生成 并将每个整数的除数的数量存储在数组中。

所以如果x = p1 ^(a1)* p2 ^ a2 * p3 ^ a3,其中p1,p2,p3是素数, x的除数总数由(p1 + 1)(p2 + 1)(p3 + 1)给出。我生成了所有 在2000以下的素数和范围内的每个整数,我做了试验分裂 获得每个素数因子的幂,然后使用上面的公式来计算 除数的数量并存储在数组中。 但是,这样做很慢,大约需要5秒才能生成分配器数量 对于给定范围内的所有数字。

我们能否以其他有效的方式做到这一点,可能没有分解每一个 数字?

以下是我现在使用的代码。

typedef unsigned long long ull;
void countDivisors(){
    ull PF_idx=0, PF=0, ans=1, N=0, power;
    for(ull i=2; i<MAX; ++i){
        if (i<SIEVE_SIZE and isPrime[i]) factors[i]=2;
        else{
        PF_idx=0;
        PF=primes[PF_idx];
        ans=1;
        N=i;
        while(N!=1 and (PF*PF<=N)){
            power = 0;
            while(N%PF==0){ N/=PF; ++power;}
            ans*=(power+1);
            PF = primes[++PF_idx];
        }
        if (N!=1) ans*=2;
        factors[i] = ans;
        }
    }
}

1 个答案:

答案 0 :(得分:3)

首先你的公式是错误的。根据你的公式,12的除数之和应为12.实际上它是28.正确的公式为(p1a1 - 1)*(p2a2 - 1) * ... * (pkak - 1)/( (p1 - 1) * (p2 - 1) * ... * (pk - 1) )

那就是说,最简单的方法可能只是做筛子。人们可以通过偏移得到聪明,但为了简单起见,只需要制作一个2,000,001个整数的数组,从0到200万。将其初始化为0。然后:

for (ull i = 1; i < MAX; ++i) {
    for (ull j = i; j < MAX; j += i) {
        factors[j] += i;
    }
}

这可能感觉效率低下,但并不是那么糟糕。截至N的数字所需的总工作量为N + N/2 + N/3 + ... + N/N = O(N log(N)),这比试验部门少了几个数量级。并且操作都是加法和比较,对整数来说很快。

如果你想继续你最初的想法和公式,你可以通过使用改良的Eratosthenes筛子来创建一个数量从1到2百万列出每个数字的主要因素,从而提高效率。构建该数组的速度相当快,您可以使用任何数字并对其进行分解,远比试用部门快得多。