数论算法.线段上的大多数除数

Number theory algorithms. Most divisors on the segment

本文关键字:大多数 算法      更新时间:2023-10-16

我正在寻找一个有效的算法来解决以下问题。设d(n)n的正因子个数,其中n为正整数。我们给定一些1 <= a <= b <= 10^18,任务是在[a..b]段上找到d的最大值,并(可能我们需要更复杂的算法)找到d的最大值。

前段时间我在免费访问中发现了以下代码:http://ideone.com/qvxPj

unsigned long long n, res;
int p, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 51, 53, 59, 61, 67, 71};
unsigned long long mul(unsigned long long a, unsigned long long b){
    unsigned long long res = 0;
    while (b){
        if (b & 1LL) res = (res + a);
        if (res >= n) return 0;
        a = (a << 1LL);
        b >>= 1LL;
    }
    return res;
}
void backtrack(int i, int lim, unsigned long long val, unsigned long long r){
    if (r > res) res = r;
    if (i == p) return;
    int d;
    unsigned long long x = val;
    for (d = 1; d <= lim; d++){
        x = mul(x, primes[i]);
        if (x == 0) return;
        backtrack(i + 1, d, x, r * (d + 1));
    }
}
int main(){    
    p = sizeof(primes) / sizeof(int);
    while (scanf("%llu", &n) != EOF){
        res = 0;
        backtrack(0, 100, 1, 1);
        printf("Maximum number of divisors of any number less than %llu = %llun", n, res);
    }
    return 0;
}

如果有人告诉我它是如何工作的,我会很高兴,因为(对我来说)这个程序运行得非常快。

提前感谢您的帮助。

它像这样遍历所有的数字:

num = P1^D1 * P2^D2 * P3^D3 * ... * Ps^Ds
constraints:
  Pi <= 71
  1 <= Di <= 100
  sequence (Pi) is a sorted list of first s primes
  sequence (Di) is nonincreasing
  num <= n

让我们检查第一个约束。设最小最优数具有质因数q> 71。若此数中不存在素数p <= 71,则可将q替换为p的同次幂。显然,除数将保持不变,但数量将减少->矛盾。那么没有小于71的未使用素数。但是71以内所有质数的乘积已经非常大了,所以我们考虑的数字必须大于64位n。那是不可能的。

现在让我们解释第二个和第三个约束。假设我们的最小最优数在其分解过程中存在素数q,但不存在素数p,其中p 。然后我们可以用p以相同的顺序替换q,这个数有相同的除数,但会变成less ->矛盾。这意味着在求最优(最小)数的因数分解中,所有质数必须恰好是第一个s质数。所使用的质数集合中不能有漏洞。顺便说一句,Di <= 100是显而易见的,因为即使2^100已经不适合64位整数了。

现在我们必须解释第四个约束。假设D[i] <D[i+1]>对于一些i。然后将P[i]^D[i] * P[i+1]^D[i+1]替换为P[i]^D[i+1] ,数量会变小。例如,将5^2 * 7^3替换为5^3 * 7^2:除数相同,但结果更小。显然,如果我们搜索最小最优数,我们也可以安全地假设这个条件。

现在让我们考虑一下代码。mul是一个计算ab乘积的小函数。它是由一个有趣的二进制程序计算出来的。这个过程的主要原因是:如果乘积大于n,则函数返回0。此过程仅用于防止可能发生的溢出。

最后,我们到了backtrack。这是一个常见的递归搜索。val是当前数,r是它的因数数,i表示我们现在要加的素数的指数,lim将每个素数的幂限制为100。在最开始,你会看到当前最优答案的更新(存储在res中),以及硬停止条件(使用所有素数)。

然后有一个循环检查当前质数的每个幂。从幂为1开始,因为幂为0是不允许的。它保持x中的当前数字,并在每次迭代中将其乘以Pi以增加功率。如果x大于n,则立即停止。最后,它调用自己来搜索下一个素数

作为@stgatilov答案的补充,我将证明选择将质数限制为小于或等于71的质数

我使用了稍微修改过的代码版本来标记具有最大除数的最大数。对于1000000000000000000或999999999999999999,我得到:

897612484786617600 = 28 * 34 * 52 * 72 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37

有103680个总因数。

这意味着对于所有18位的十进制数字,不涉及大于37的质数是找到除数最多的整数