繁体   English   中英

如果组的总和至少为K,则从数组中选择元素的方式的数量

[英]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)) 我们将这两个排序的集合称为FL (分别用于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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM