链接:https://www.nowcoder.com/acm/contest/94/K
来源:牛客网
时间限制:C/C++ 5秒,其他语言10秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述
小马哥有杯盐水,第杯有单位的盐和单位的水。小马哥很无聊,于是他想知道有多少种这杯盐水的非空子集,倒在一起之后盐和水的比是
输入描述:
输入第一行包含一个整数,代表数据组数。
每组数据第一行包含三个整数表示和的最大公约数。
接下来行,第行包含两个整数
输出描述:
每组数据输出一行,包含一个整数表示非空子集的个数。
示例1
输入
1 5 1 2 1 2 1 2 1 2 1 2 1 4
输出
15
n <= 35 如果直接枚举状态肯定超时,但如果枚举 n/2的状态就不会超时,所以可以把n分成两份,分别枚举状态,根据第一份的状态,二分搜索第二份的状态即可。
状态公式:(ai + aj) / ( bi + bj) = x / y
=> y * (ai + aj) = x * (bi + bj)
=> ai * y - bi * x = bj * x - aj * y
记录每个状态的 b和 * x - a和 * y就能得出答案。
附ac代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <vector> 6 #include <cmath> 7 #include <string> 8 using namespace std; 9 typedef long long ll; 10 const int maxn = 400000; 11 ll a[maxn], b[maxn]; 12 ll ansa[maxn], ansb[maxn]; 13 int t; 14 int n; 15 ll x, y; 16 int lea = 0; 17 void dfsa(int now, ll sum) { 18 if(now == n / 2) { 19 ansa[lea++] = sum; 20 return; 21 } 22 dfsa(now + 1, sum); 23 dfsa(now + 1, sum + (x * b[now] - y * a[now])); 24 25 return; 26 } 27 int leb = 0; 28 void dfsb(int now, int sum) { 29 if(now == n) { 30 ansb[leb++] = sum; 31 return; 32 } 33 dfsb(now + 1, sum); 34 dfsb(now + 1, sum + (x * b[now] - y * a[now])); 35 36 return; 37 } 38 int main() { 39 40 scanf("%d", &t); 41 while(t--) { 42 lea = 0; 43 leb = 0; 44 scanf("%d %lld %lld", &n, &x, &y); 45 for(int i = 0; i < n; ++i) { 46 scanf("%lld %lld", &a[i], &b[i]); 47 } 48 dfsa(0, ll(0)); 49 dfsb(n / 2, ll(0)); 50 // printf("%d %d ", lea, leb); 51 ll cnt = 0; 52 sort(ansb, ansb + leb); 53 for (int i = 0; i < lea; i++) 54 cnt += (upper_bound(ansb, ansb + leb, -ansa[i]) - ansb) - (lower_bound(ansb, ansb + leb, -ansa[i]) - ansb); 55 56 printf("%lld ", cnt - 1); 57 } 58 return 0; 59 }