📜  计算给定范围内不同总和子集的数量

📅  最后修改于: 2021-05-25 01:00:42             🧑  作者: Mango

给定N个数字的集合S,以及两个数字L(下界)和R(上界)指定的范围。找出介于给定范围内的S的某个子集的所有可能总和的不同值的数量。

例子 :

Input : S = { 1, 2, 2, 3, 5 }, L = 1 and R = 5
Output : 5
Explanation :  Every number between 
1 and 5 can be made out using some subset of S.
{1 as 1, 2 as 2, 3 as 3, 4 as 2 + 2 and 5 as 5} 

Input : S = { 2, 3, 5 }, L = 1 and R = 7
Output : 4
Explanation :  Only 4 numbers between 
1 and 7 can be made out, i.e. {2, 3, 5, 7}. 
3 numbers which are {1, 4, 6} can't be made out in any way.

先决条件:位集|位操作

方法1(简单):天真的方法是生成给定集合的所有可能子集,明智地计算它们的总和子集,并将其推入哈希图中。遍历给定的完整范围并计算哈希图中存在的数字。

方法2(有效):解决此问题的有效方法是使用大小为10 5的位集。通过左移位元组并与先前的位元组进行按位“或”操作,以更新每个元素X的位元组,以使新的可能总和的位元组变为1。然后使用“前缀和”的概念,预先计算所需的1到i之间的数字计数如果有多个查询同时被请求,则使用prefix [1..i]来回答O(1)中的每个查询。对于查询L和R,答案将只是prefix [R] – prefix [L – 1]

下面是上述方法在C++中的实现:

// CPP Program to count the number
// distinct values of sum of some
// subset in a range
#include 
  
using namespace std;
  
// Constant size for bitset
#define SZ 100001
  
int countOfpossibleNumbers(int S[], int N, 
                           int L, int R)
{
    // Creating a bitset of size SZ
    bitset  BS;
      
    // Set 0th position to 1
    BS[0] = 1;
      
    // Build the bitset
    for (int i = 0; i < N; i++) {
          
        // Left shift the bitset for each
        // element and taking bitwise OR
        // with previous bitset
        BS = BS | (BS << S[i]);
    }
      
    int prefix[SZ];
      
    // Intializing the prefix array to zero
    memset(prefix, 0, sizeof(prefix));
      
    // Build the prefix array
    for (int i = 1; i < SZ; i++) {
        prefix[i] = prefix[i - 1] + BS[i];
    }
      
    // Answer the given query
    int ans = prefix[R] - prefix[L - 1];
      
    return ans;
}
  
// Driver Code to test above functions
int main() 
{
    int S[] = { 1, 2, 3, 5, 7 };
    int N = sizeof(S) / sizeof(S[0]);
      
    int L = 1, R = 18;
      
    cout << countOfpossibleNumbers(S, N, L, R);
          
    return 0;
} 
输出:
18

时间复杂度: O(S * Z)其中S * Z是给定约束的最大和,即10 5