给定一个由N个正整数和M个查询组成的array []。每个查询由范围表示的两个整数L和R组成。对于每个查询,找到位于给定范围内的数字计数,该数量可以表示为给定数组的任何子集的总和。
先决条件:使用位集的子集总查询
例子:
Input : arr[] = { 1, 2, 2, 3, 5 }, M = 4
L = 1, R = 2
L = 1, R = 5
L = 3, R = 6
L = 9, R = 30
Output :
2
5
4
5
Explanation : For the first query, in range [1, 2] all numbers i.e. 1 and 2 can be expressed as a subset sum, 1 as 1, 2 as 2. For the second query, in range [1, 5] all numbers i.e. 1, 2, 3, 4 and 5 can be expressed as subset sum, 1 as 1, 2 as 2, 3 as 3, 4 as 2 + 2 or 1 + 3, 5 as 5. For the third query, in range [3, 6], all numbers i.e. 3, 4, 5 and 6 can be expressed as subset sum. For the last query, only numbers 9, 10, 11, 12, 13 can be expressed as subset sum, 9 as 5 + 2 + 2, 10 as 5 + 2 + 2 + 1, 11 as 5 + 3 + 2 + 1, 12 as 5 + 3 + 2 + 2 and 13 as 5 + 3 + 2 + 2 + 1.
方法:想法是使用位集并在数组上进行迭代以表示所有可能的子集和。比特集的当前状态是通过将其与左移位X的先前比特集状态进行“或”运算来定义的,其中X是数组中当前处理的元素。为了在O(1)时间内回答查询,我们可以预先计算最多每个数字的数量,对于[L,R]范围,答案将是pre [R] – pre [L – 1] ,其中pre []是预先计算的数组。
下面是上述方法的实现。
// CPP Program to answer subset
// sum queries in a given range
#include
using namespace std;
const int MAX = 1001;
bitset bit;
// precomputation array
int pre[MAX];
// structure to represent query
struct que {
int L, R;
};
void answerQueries(int Q, que Queries[], int N,
int arr[])
{
// Setting bit at 0th position as 1
bit[0] = 1;
for (int i = 0; i < N; i++)
bit |= (bit << arr[i]);
// Precompute the array
for (int i = 1; i < MAX; i++)
pre[i] = pre[i - 1] + bit[i];
// Answer Queries
for (int i = 0; i < Q; i++) {
int l = Queries[i].L;
int r = Queries[i].R;
cout << pre[r] - pre[l - 1] << endl;
}
}
// Driver Code to test above function
int main()
{
int arr[] = { 1, 2, 2, 3, 5 };
int N = sizeof(arr) / sizeof(arr[0]);
int M = 4;
que Queries[M];
Queries[0].L = 1, Queries[0].R = 2;
Queries[1].L = 1, Queries[1].R = 5;
Queries[2].L = 3, Queries[2].R = 6;
Queries[3].L = 9, Queries[3].R = 30;
answerQueries(M, Queries, N, arr);
return 0;
}
2
5
4
5
时间复杂度:每个查询都可以在O(1)时间内回答,并且预计算需要O(MAX)时间。