SPOJ SUBSUMS Subset Sums 折半枚举

来源:互联网 发布:ubuntu kylin qq 编辑:程序博客网 时间:2024/05/22 15:13

题目:

http://www.spoj.com/problems/SUBSUMS/en/

题意:

整数集S有n个元素,问S的子集和落在区间[A,B]中的个数

思路:

直接枚举肯定会T的,可以折半枚举,分成两个整数集,分别求出两个整数集的所有子集和,设子集和的集合分别为S1,S2,对于aS1,假如有bS2,使得a+b[A,B],那么一定有b[Aa,Ba],事先对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;}
0 0
原创粉丝点击