题目:
http://www.spoj.com/problems/SUBSUMS/en/
题意:
整数集S有n个元素,问S的子集和落在区间[A,B]中的个数
思路:
直接枚举肯定会T的,可以折半枚举,分成两个整数集,分别求出两个整数集的所有子集和,设子集和的集合分别为 S1,S2 ,对于 a∈S1 ,假如有 b∈S2 ,使得 a+b∈[A,B] ,那么一定有 b∈[A−a,B−a] ,事先对S2排序,就可以用二分搜索确定满足条件的b的个数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50, M = 1<<18;
ll arr[M+10], brr[M+10];
//二进制枚举子集和,用dfs枚举也可以
int work(ll *arr, int *tm, int m, int len)
{
int k = 0;
for(int i = 0; i < (1<<m); i++)
{
for(int j = 0; j < m; j++)
if(i & (1<<j)) arr[k] += tm[len-1-j];
k++;
}
return k;
}
int main()
{
int n;
ll a, b;
int tm[N];
scanf("%d%lld%lld", &n, &a, &b);
for(int i = 0; i < n; i++)
scanf("%d", &tm[i]);
int len = n/2;
int k1 = work(arr, tm, len, len);
int k2 = work(brr, tm, n-len, n);
sort(arr, arr + k1);
sort(brr, brr + k2);
ll res = 0;
for(int i = 0; i < k1; i++)
{
res += upper_bound(brr, brr + k2, b-arr[i]) - lower_bound(brr, brr + k2, a-arr[i]);
}
printf("%lld\n", res);
return 0;
}