数论算法。该细分市场上的大多数除数

时间:2015-07-28 12:35:48

标签: c++ algorithm numbers number-theory

我正在寻找一种有效的算法来解决以下问题。设n表示n的正除数的数量,其中1 <= a <= b <= 10^18是正整数。我们给了一些d,任务是在段[a..b]上找到d的最大值,并且(可能我们需要更复杂的算法)来查找最大化值的数字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 = %llu\n", n, res); } return 0; }

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

TABLE_NAME

如果有人向我解释它是如何工作的,我将非常高兴,因为(至于我)这个程序运行得非常快。

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

它遍历所有这样的数字:

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&lt; = 71 ,则我们可以用相同的幂替换 q p 。显然,除数的数量将保持不变,但数量会减少 - &gt;矛盾。然后没有未使用的素数低于71.但是所有素数高达71的产品已经非常庞大,我们考虑的数量必须大于64位 n 。那是不可能的。

现在让我们解释第二个和第三个约束。假设我们的最小最优数在其因子分解中具有素数 q ,但是没有一些素数 p ,其中 p q 。然后我们可以用相同的顺序用 p 替换 q ,数字将具有相同数量的除数,但它会变得更少 - &gt;矛盾。这意味着所寻求的最优(最小)数的因子分解中的所有素数必须恰好是第一个 s 素数。使用的素数组中不能有空洞。 BTW, Di&lt; = 100 是显而易见的,因为即使2 ^ 100也不适合64位整数。

现在我们要解释第四个约束。假设 D [i]&lt;某些 i 的D [i + 1] 。然后我们可以用 P [i] ^ D [i + 1] *替换 P [i] ^ D [i] * P [i + 1] ^ D [i + 1] P [i + 1] ^ D [i] ,数字会变小。例如,用5 ^ 3 * 7 ^ 2替换5 ^ 2 * 7 ^ 3:除数的数量相同,但结果更小。显然,如果我们搜索最小的最优数,我们也可以安全地假设这个条件。

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

最后,我们到了backtrack。这是一种通常的递归搜索。 val是当前的数字,r是其除数的数量,i显示我们现在要添加的素数的索引,lim限制每个素数的幂100.一开始你会看到当前最佳答案的更新(存储在res中)和硬停止条件(所有使用的素数)。

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

答案 1 :(得分:1)

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

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

  

897612484786617600 = 2 8 * 3 4 * 5 2 * 7 2 * 11 * 13 * 17 * 19 * 23 * 29 * 31 * 37

总共有103680个除数。

这意味着对于所有18个十进制数字的数字,没有涉及大于37的素数是找到具有最大除数的整数。