[英]Number of ways to choose elements from array if the sum of the group is at least K
问题:如果我们给定整数N,K和大小为N的数组,使得1 <= N <= 36,并且数组中的每个整数都是<= 10 ^ 13。 现在,我们必须指望可以从数组中获取元素的方式有多少种,以使这些元素的总和至少为K
这是一个示例:N = 4,K = 6,array = {1,2,5,4}答案是9,因为我们可以通过9种不同的方式从数组中获取元素,并且它们的和至少为K,答案是要素(第一和第三); (第二和第三); (第一,第二和第三); (第二和第四); (第一,第二和第四); (第一,第三和第四); (第二,第三和第四); (第一,第二,第三和第四); (第三和第四)。
我的想法是使用位掩码,我们可以搜索所有组合并选择是否接受,但这复杂度为O(2 ^ N),在我们的情况下为N <= 36,这太慢了。
对于此问题,您可以使用类似于通常用于解决时间为O(N*2^(N/2))
的子集和问题的“中间技巧”。复杂)。
首先,计算前N/2
元素的2^N/2
可能的和,并存储它们。 对最后N/2
元素执行相同的操作。
现在按升序对两个集合进行排序。 对n
元素进行排序需要时间O(n log n)
,因此这里的成本为O(N 2^(N/2))
。 我们将这两个排序的集合称为F
和L
(分别用于First和Last)。
然后,执行以下操作:
设置res = 0
从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)
}
返回资源
这个想法是,对于前N/2
元素的每个子集,您查看有多少种方法可以选择后N/2
元素的子集,以使总和大于K
为此,您只需要在最后一个元素的子集的总和中找到实现此目标的最小值,然后知道总和至少等于该值的子集就是与初始元素组合的子集。总和大于或等于K
子集,对它们进行计数很容易,因为您对可能值的数组进行了排序。
PS:通过使用最小j_i
的序列(使得F[i] + L[j_i] >= K
是一个非递增序列的事实,可以进行边际优化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.