给定范围内的求和与乘积

7

给定四个正整数S_1, S_2, P_1P_2,是否有一种快速找到任意两个整数ab的方法,使得:

  • S_1 \leq a+b \leq S_2,和
  • P_1 \leq ab \leq P_2
S_1 = S_2P_1 = P_2 时,使用二次方程式可以得到一个闭合形式的 O(1) 解决方案。我们只需找到 a^2 - S_1*a + P_1 的根,就能得到一个适当的 a

S_1 = S_2时,我知道如何通过注意到曲线f(a) = a(S_1 - a)是凸的,所以我们可以二分搜索适当的a,从而在O(log S_1)中解决它。

P_1 = P_2时,可以通过对P_1进行因式分解,并查找在范围内求和的一对因子来解决O(sqrt P_1)。请注意保留HTML标记。

然而,当两个都是范围时,我想不出任何可以高效解决此问题的算法。有一些可能的启发式方法,比如固定其中一个(遍历较小的范围等),或者在两个整数之和为S_2时可以制造的最大可能乘积小于P_1时立即报告不存在任何一对等。

很遗憾,我还没有想出任何比迭代O(|S_2-S_1|)O(|P_2-P_1|)(可能带有一些额外的小因子)更快的通用解决方案。是否有一种好的算法或一些花哨的数学方法可以提供更快的解决方案?

另外,是否有一种方法可以证明迭代会迅速终止?(在处理一些边缘情况等之后。)我不关心有效对数的数量;找到任何一对即可。如果允许的总和范围足够大,则迭代乘积并尝试找到相应的总和似乎很快就能找到解决方案。这是否可能有某种证明呢?

我非常感谢任何帮助!


S1S2P1P2的范围有限制吗?例如,如果它们都是严格正数,那么解决起来应该比一般情况更容易,因为例如ab都不能大于或等于S2P2。因此,搜索范围限制为1..min(S2, P2) - twalberg
是的,它们保证是正数;我认为即使这个版本也足够困难。我已经更新了问题;感谢您的澄清! - Robin Yu
只是一个观察,但是 max(S1 - b, P1/b) <= a <= min(S2 - b, P2/b)。也许描述这个不等式可以帮助找到 O(1) 的解决方案。 - darksky
1个回答

3
您可以在O(sqrt(P2))时间内解决它。
1. 找到这些总和:small_sum = i + ceiling(P1/i)和big_sum = i + floor(P2/i),其中i在1到sqrt(P2)之间。 2. 如果small_sum > big_sum或big_sum < s1或small_sum > s2,则i不是解的一部分。继续下一个i。 3. 否则,max(small_sum, s1) min(big_sum, s2),以及所有“好总和”之间的值。对于其中任何一个,让j = good_sum - i。然后i + j是s1和s2之间的值,而i * j是p1和p2之间的值。 我们检查最多sqrt(P2)个i值,并且对于每个这些值,我们都会进行恒定的工作。
编辑 - Ruby实现
def solve(s1, s2, p1, p2)
  max_i = (p2**0.5).floor
  1.upto(max_i) do |i|
    small_sum = i + (p1/i.to_f).ceil
    big_sum = i + (p2/i.to_f).floor
    next if big_sum < s1 || small_sum > s2 || big_sum < small_sum
    good_sum = [small_sum, s1].max
    puts "sum: #{i} + #{good_sum - i} = #{good_sum}, #{s1} <= #{good_sum} <= #{s2}"
    puts "product: #{i} * #{good_sum-i} = #{i*(good_sum-i)}, #{p1} <= #{i*(good_sum-i)} <= #{p2}"
    return
  end
  puts "no solution"
end

我还没有完全理解为什么(以及是否)您的解决方案总是有效的,但我不认为O(log P_2)“二分查找”解决方案是正确的;如果它是正确的,我们可以通过设置S1 = 1,S2 = n,P1 = P2 = n并运行您的算法来查找一对,以在O(log n)中找到n的非平凡因子。但整数因子分解是一个困难的问题。 - Robin Yu
话虽如此,我刚刚测试了一下,这个算法似乎不正确。在查询S1 = 1,S2 = 99,P1 = 99,P2 = 99时,它给出a = 5,b = 20,但是5 * 20 = 100,而不是99。一些正确的输出应该是a = 3,b = 33或a = 9,b = 11。也许这只是一个错误,至少我希望如此。https://repl.it/JPYG - Robin Yu
你说得对。需要检查所有的i。我会尽快修复它。平方根时间。 - Dave
@RobinYu,我已经恢复了正确的代码。现在试试看。对于二分查找我感到抱歉——我在离开之前突然有了一个“灵感”,进行了快速更改而没有检查它。 - Dave
新版本似乎是正确的,我现在有点理解它的工作原理了。我已经点赞并接受了 - 谢谢! - Robin Yu
你实际上不需要从1开始;你可以从(x^2) + (s2 * x) - (p1)的最小正解的上限开始(利用当b-a最大时a是最小的这一事实)。如果给出了不可能的s2值,需要小心处理。 - Dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接