C++11 动态规划中极限的计算

C++11 动态规划中极限的计算,c++11,math,dynamic,C++11,Math,Dynamic,我在topcoder上发现了这个问题: 你的朋友卢卡斯给了你一个正整数序列 有一段时间,你们两个和S玩了一个简单的游戏:Lucas会选择一个数字,你必须选择S的一些元素,这样你选择的所有数字的总和就是Lucas选择的数字。例如,如果S={2,1,2,7}并且Lucas选择了数字11,您将回答2+2+7=11 卢卡斯现在想通过选择一个数字X来欺骗你,这样就不会有有效的答案。例如,如果S={2,1,2,7},则不可能选择S的元素总和为6 给定int[]S。查找无法作为S的某些(可能所有)元素之和获得

我在topcoder上发现了这个问题:

你的朋友卢卡斯给了你一个正整数序列

有一段时间,你们两个和S玩了一个简单的游戏:Lucas会选择一个数字,你必须选择S的一些元素,这样你选择的所有数字的总和就是Lucas选择的数字。例如,如果S={2,1,2,7}并且Lucas选择了数字11,您将回答2+2+7=11

卢卡斯现在想通过选择一个数字X来欺骗你,这样就不会有有效的答案。例如,如果S={2,1,2,7},则不可能选择S的元素总和为6

给定int[]S。查找无法作为S的某些(可能所有)元素之和获得的最小正整数X

约束:-S将包含1到20个元素,包括-S的每个元素将介于1和100000之间(含1和100000)

但在《编辑解决方案》中写道:

找到最小的不可能的和怎么样?好的,我们可以尝试以下简单的算法:首先尝试x=1,如果这不是一个有效的和(使用上一节中的方法找到),那么我们可以返回x,否则我们增加x,然后重试,直到找到不是有效和的最小数

让我们找到迭代次数的上界,即在找到结果之前需要尝试的x值的数量。首先,这个问题中可能的最大和是100000*20(所有数字都是最大100000),这意味着100000*20+1不是一个不可能的值。我们肯定最多需要2000001个步骤

这个上限有多好?如果20个数字中的每一个都有100000,那么1就不可能是一个总数。在这种情况下,我们实际上需要一次迭代。如果我们希望1是一个可能的和,我们应该在初始元素中有1。然后我们需要一个2(否则我们只需要2次迭代),然后是4(3可以通过1+2相加得到),然后是8(5到7的数字可以通过2的前3次幂相加得到),然后是16,32。。。。事实证明,使用2的幂,我们可以轻松地进行需要多次迭代的输入。使用2的前17次幂,我们最多可以覆盖前262143个整数。对于最大的数字来说,这应该是一个很好的估计。(我们不能在输入中使用2^18,小于100000)

最多262143次,我们需要查询数字x是否在可能的和集合中。我们可以在这里使用布尔数组。然而,即使是O(log(n))数据结构也应该足够快

我确实理解了第一段。但在那之后,他们解释了一些关于“这个上限有多好?”。我看不懂那一段。如果一个数字x在一组可能的和中,他们是如何推断出我们需要查询262143次这个事实的

我是动态规划的新手,所以如果有人能给我解释一下,那就太好了


谢谢。

想法如下:

如果输入序列包含两个幂的第一个
k
幂:
2^0,2^1。。。2^(k-1)
,则总和可以是
0
(2^k)-1
之间的任何整数。由于序列中出现的两个数的最大幂是
2^17
,因此从18个数中可以得到的最大和是
2^18-1=262143
。如果缺少2的幂,那么将有一个不可能实现的较小的总和

但是,缺少一条语句,即序列中可能还有2个数字(最多20个)。从这两个数字中,您可以重复相同的过程。因此,要检查的最大数量实际上是
(2^18)-1+(2^2)-1

你可能想知道为什么我们使用两个幂而不是任何其他幂。原因是我们对输入序列中的数字执行的二进制选择。我们要么给总数加一个数字,要么不加。因此,如果我们将数字
ni
的选择表示为选择变量
si
(0或1),则可能的总和为:

s = s0 * n0 + s1 * n1 + s2 * n2 + ...
现在,如果我们选择
ni
作为两个
ni=2^i
的幂,那么:

s = s0 * 2^0 + s1 * 2^1 + s2 * 2^2 + ...
  = sum si * 2^i
这相当于数字的二进制表示(请参阅)。根据定义,选择变量的不同选择将产生不同的和。因此,通过在输入序列中选择二的幂,可能和的数目是最大的