【问题标题】:Algorithm about number theory关于数论的算法
【发布时间】:2013-12-14 13:57:10
【问题描述】:

给定两个正整数a,b (1

L = {x * y | 1 <= x <= a, 1 <= y <= b, x,y is integer}

R = {x ^ y | 1 <= x <= a, 1 <= y <= b, x,y is integer},

^ 是异或运算

对于任意两个整数:A∈L,B∈R,我们将B格式化为n+1(n为b的十进制数)十进制数(B前面填0),然后将B连接到结束A,得到一个新的整数AB。

计算所有生成的整数AB的总和(如果总和超过,则返回“sum mod 1000000007”,mod表示模运算)

注意:你的算法时间不超过3秒

我的算法很简单:我们可以很容易的得到集合R中的最大值,R中的元素是0,1,2,3...maxXor,(元素max( a,b) 可能不在 R) 中,使用哈希表计算集 L。但是当 a = 30, b = 100000 时算法消耗 4 秒


举个例子:

a = 2, b = 4, so

L = {1 * 1, 1 * 2, 1 * 3, 1 * 4, 2 * 1, 2 * 2, 2 * 3, 2 * 4} =  {1, 2, 3, 4, 6, 8}

R =  {1^1,1^2,1^3,1^4,2^1,2^2,2^3,2^4} =  {0, 1, 2, 3, 5, 6}

所有生成的整数AB是:

{

100, 101, 102, 103, 105, 106,

200, 201, 202, 203, 205, 206,

300, 301, 302, 303, 305, 306,

400, 401, 402, 403, 405, 406,

600, 601, 602, 603, 605, 606,

800, 801, 802, 803, 805, 806

}

所有AB总和14502

【问题讨论】:

  • 您需要发布您的代码,以便人们可以看到哪里(如果有的话)做错了。
  • 也许你应该根据复杂性来定义性能要求,因为,你知道,我有一台很棒的超级计算机,而且它在不到 3 秒内就完成了
  • @dkrikun 这听起来像是编程竞赛的问题 - 这些通常使用中档计算机,并且给出时间复杂度要求。
  • 你是如何构建集合 L 的?请出示您的代码。
  • @splrs 我 psot 我的代码

标签: c++ algorithm


【解决方案1】:

所以数字 AB 可以写成10^(n+1) A + B。这意味着对所有A, B求和,总数等于

|R| 10^(n+1) Sum(A in L) + |L| Sum(B in R)

在你的例子中,

|L| = 6
|R| = 6
Sum(A in L) = 24
Sum(B in R) = 17
n = 3

代入上述公式后得到 14,502。

这将集合大小的运行时间从二次变为线性,因此您应该会看到相当大的改进。

接下来的部分我没有完全充实,因为我没有时间,但他们觉得他们应该工作:

  • 首先,请注意Sum(A in L) 使用计算很简单

    1 + 2 + .. + n = n(n-1)/2
    

    如果没有L 不包含重复的约束。不过,您可以通过利用 a 非常小的事实来解决此问题:使用三角数公式迭代地计算总和 1, .., a 并使用该信息来避免多次计算产品。

  • 对于Sum(B in R),请注意,当您比较yx^y 时,最多第一个lg(a) 位已更改。因此,您可以将x^ys 的总和分成两个总和:一个处理来自lg(a)+1 向上的位并且仅依赖于b,另一个更复杂的总和处理来自@987654339 的位@ 向下,取决于ab

编辑:OP 要求我扩展如何快速计算 Sum(A in L)。在之前的编辑中,这部分有很多东西,但实际上我现在已经坐下来仔细研究了它,而不是随意地在脑海中敲打它。结果也比我预期的要复杂,所以我很抱歉没有坐下来尽快解决它@tenos。

所以我们要做的是取所有不同产品的总和x*y,这样1 &lt;= x &lt;= a1 &lt;= y &lt;= b。好吧,事实证明这很难,所以让我们从一个更简单的问题开始:给定两个整数 x1, x2x1 &lt; x2,我们如何计算所有不同乘积的总和 x1*yx2*y 其中1 &lt;= y &lt;= b

如果我们放弃了独特性标准,这很容易:它只是

x1*Sum(b) + x2*Sum(b)

其中Sum(j) 表示整数1j 的总和,可以使用三角数的高斯公式计算。因此,我们可以再次将问题简化为更简单的问题:我们如何才能找到同时出现在左右项中的所有产品的总和?

嗯,如果两个产品相等

x1*y1 == x2*y2

这恰好在x1*y1 == x2*y2 == k*LCM(x1, x2) 时发生,其中LCMlowest common multiplek 是某个整数。

所有k 的总和使得1 &lt;= k*LCM(x1, x2) &lt;= x1*b

R(x1, x2) = LCM(x1, x2) * Sum(x1*b/LCM(x1, x2))

R 代表“重复”。这意味着我们所有不同产品的总和 x1*yx2*y 其中1 &lt;= y &lt;= b

x1*Sum(b) + x2*Sum(b) - R(x1, x2)

接下来,我们将R的定义扩展为定义在三个变量x1 &lt; x2 &lt; x3

R(x1, x2, x3) = LCM(x1, x2, x3) * Sum(x1*b/LCM(x1, x2, x3))

对于 4 个变量、5 个变量等类似。那么三个 x1 &lt; x2 &lt; x3 的不同乘积之和为

x1*Sum(b) + x2*Sum(b) + x3*Sum(b) - R(x1, x2) - R(x1, x3) - R(x2, x3) + R(x1, x2, x3)

inclusion-exclusion principle

所以,让我们利用它。定义

Sum for x = 1: 1*Sum(b)
Sum for x = 2: 2*Sum(b) - R(2, 1)
Sum for x = 3: 3*Sum(b) - R(3, 2) - R(3, 1) + R(3, 2, 1)

等等。那么直到x = a 的所有这些总和的总和就是所有不同乘积的总和。

编辑:@tenos 把它变成了一个有用的解决方案。他注意到由于 i*Sum(b) 包含许多重复,我们可以替换为 i*sum(k...b), k = max(b/minPrimeFactor(i) + 1, i)。

此外,当使用包含-排除原则时,可以修剪许多不必要的计算。例如,如果 R(1,2) = NULL,则不需要计算 R(1,2,3)、R(1,2,4).. 等。实际上,当 b 很大时,有很多 R(i,..j) = NULL。

【讨论】:

  • 感谢您的回答。元素 int set L 不连续,因此 sum(L) = 1 + 2 + .. + n = n(n-1)/2 不起作用。顺便说一句,我不明白“将 1、..、a 中的每个数字分解为素数并使用该信息来避免多次计算产品”。
  • 当 a = 4, b = 6 时,用你的方法计算 L:1*(1...6), 2*(4,5,6), 3*(3,4 ,5,6), 4*(4,5,6),但 2*6 和 3*4 都等于 12。L 仍然包含重复。
  • @tenos 发布了更严格的方法。结果比我想象的要复杂。明天下午会自己编写代码并测试它,但我说我会在早上之前给你一些东西,所以我想我会给你我手工完成的实例的工作原理。等我先测试一下,如果可以的话,如果它错了,宁愿不要再浪费你的时间了。
  • 目前,我没有想出更好的方法。如果找到一个,我会改进这个问题。顺便说一句,感谢您的所有回答。
  • 嗨,安迪,我已经解决了这个问题。你的方法是对的。我使用一些技巧来修剪一些不必要的计算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 2012-10-27
相关资源
最近更新 更多