给定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]
For e.g. S = { 2, 3, 5 }, L = 1 and R = 7
Considering a bitset of size 32 for simplicity. Initially 1 is at 0th position of bitset
00000000000000000000000000000001
For incoming 2, left shifting the bitset by 2 and doing OR with previous bitset
00000000000000000000000000000101
Similarly for 3,
00000000000000000000000000101101
for 5,
00000000000000000000010110101101
This final bitset contains 1 at those positions(possible sums) which can be made out using some
subset of S. Hence between position 1 and 7, there are 4 set bits, thus the required answer.
下面是上述方法在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