30-盐水(分段dfs)

链接:https://www.nowcoder.com/acm/contest/94/K
来源:牛客网

时间限制:C/C++ 5秒,其他语言10秒
空间限制: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不能直接深搜,会爆的,所以可以将其分为两部分深搜去求和,又(a1 + a2)/ (b1 + b2) == x / y; 变形为: b1 * x - a1 * y == a2 * y - b2 * x; 可见分为了互不影响的两部分,a1,b1为第一个dfs求和,b2,a2为第二个
dfs求和,最后只有互为相反数即可为一组x/y的组合,同时可以转为map标记。
注意:数据范围。
#include <bits/stdc++.h>
using namespace std;
map <long long, long long> mp; //要用long long,因为sa = 1e4 * 35, x = 1e4, sa * x < 3e9超int了 
long long ans; 
int a[40], b[40];
int x, y, n;

void dfs_before(int k, int sa, int sb){
	if(k > n / 2){
		mp[x * sb - sa * y]++;
		return ;
	}
	dfs_before(k + 1, sa + a[k], sb + b[k]);
	dfs_before(k + 1, sa, sb);
}

void dfs_after(int k, int sa, int sb){
//	cout << k << endl; 
	if(k >= n){
		ans += mp[sa * y - sb * x];
		return ;
	}
	dfs_after(k + 1, sa + a[k], sb + b[k]);
	dfs_after(k + 1, sa, sb);
}

int main(){
	std::ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while(t--){
		ans = 0;
		mp.clear(); 
		cin >> n >> x >> y;
		for(int i = 0; i < n; i++){
			cin >> a[i] >> b[i];
		}
		int m = n / 2;
		dfs_before(0, 0, 0);
		dfs_after(m + 1, 0, 0);
		cout << ans - 1 << endl;  //要减去一:sa = sb = 0的情况要除去,虽然符合推导的表达式,但是显然不合题意 
	}
	return 0;
} 

  

 
原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/8858444.html