问题:如果我们给出整数N,K和大小为N的数组,使得1 <= N <= 36, 并且数组中的每个整数都是&lt; = 10 ^ 13。现在我们必须指望我们可以从数组中获取元素的不同方式,以便这些元素的总和至少为K
这是一个例子:N = 4,K = 6,数组= {1,2,5,4} 答案是9,因为我们可以用九种不同的方式从数组中获取元素,它们的总和至少为K,答案是元素(第一和第三); (第二和第三); (第一,第二和第三); (第二和第四); (第一,第二和第四); (第一,第三和第四); (第二,第三和第四); (第一,第二,第三和第四); (第三和第四)。
我的想法是使用比特掩码,我们可以搜索所有组合,并选择我们应该采取或不应该,但是它具有O(2 ^ N)的复杂度,在我们的情况下N <= 36其中太慢了。
答案 0 :(得分:2)
对于这个问题,你可以在中间技巧中使用&#39;类似于通常用于解决时间O(N*2^(N/2))
中的子集求和问题的那个(并且您将具有相同的复杂性)。
首先,计算第一个2^N/2
元素的N/2
可能总和,然后存储它们。对最后的N/2
元素执行相同的操作。
现在按递增顺序对两个集合进行排序。对n
元素进行排序需要花费时间O(n log n)
,因此这需要O(N 2^(N/2))
费用。让我们调用这两个排序集F
和L
(对于First和Last)。
然后,执行以下操作:
设置res = 0
表示i从0到2 ^(N / 2)-1 {
在{0,..,2 ^(N / 2)-1}中找到最小j_i,使得F [i] + L [j_i]> = K(使用二分法搜索)
如果存在这样的j_i,则将res增加(2 ^(N / 2) - j_i)
}
返回res
我们的想法是,对于第一个N/2
元素的每个子集,您可以查看有多少种方法可以选择最后N/2
元素的子集,以使总和高于{{ 1}}。为此,您只需要找到在最后一个元素的子集总和中实现此值的最低值,然后您就会知道总和为至少一个值的子集恰好是与初始元素组合的子集。总和大于或等于K
的子集,由于您对可能值的数组进行了排序,因此计算这些数据很容易。
P.S:通过使用最小K
序列使j_i
为非递增序列这一事实,可以实现边际优化。