Luogu P3067 [USACO12OPEN]Balanced Cow Subsets G

题面翻译

我们定义一个奶牛集合 S S S 是平衡的,当且仅当满足以下两个条件:

  • S S S 非空。
  • S S S 可以被划分成两个集合 A , B A,B A,B,满足 A A A 里的奶牛产奶量之和等于 B B B 里的奶牛产奶量之和。划分的含义是, A ∪ B = S A\cup B=S AB=S A ∩ B = ∅ A\cap B=\varnothing AB=

现在给定大小为 n n n 的奶牛集合 S S S,询问它有多少个子集是平衡的。请注意,奶牛之间是互不相同的,但是它们的产奶量可能出现相同。

输入格式

第一行一个整数 n n n,表示奶牛的数目。

2 2 2 n + 1 n+1 n+1 行,每行一个数 a i a_i ai,表示每头奶牛的产奶量。

输出格式

输出一个数表示方案总数。

样例解释

共存在三种方案。集合 { 1 , 2 , 3 } \{1,2,3\} {1,2,3} 可以划分为 { 1 , 2 } \{1,2\} {1,2} { 3 } \{3\} {3};集合 { 1 , 3 , 4 } \{1,3,4\} {1,3,4} 可以划分为 { 1 , 3 } \{1,3\} {1,3} { 4 } \{4\} {4};集合 { 1 , 2 , 3 , 4 } \{1,2,3,4\} {1,2,3,4} 可以划分为 { 1 , 4 } \{1,4\} {1,4} { 2 , 3 } \{2,3\} {2,3},共 3 3 3 种子集。

数据范围及约定

对于全部数据,保证 1 ≤ n ≤ 20 1\le n\le 20 1n20 1 ≤ a i ≤ 1 0 8 1\le a_i\le 10^8 1ai108

题目描述

Farmer John’s owns N cows (2 <= N <= 20), where cow i produces M(i) units of milk each day (1 <= M(i) <= 100,000,000). FJ wants to streamline the process of milking his cows every day, so he installs a brand new milking machine in his barn. Unfortunately, the machine turns out to be far too sensitive: it only works properly if the cows on the left side of the barn have the exact same total milk output as the cows on the right side of the barn!

Let us call a subset of cows “balanced” if it can be partitioned into two groups having equal milk output. Since only a balanced subset of cows can make the milking machine work, FJ wonders how many subsets of his N cows are balanced. Please help him compute this quantity.

输入格式

* Line 1: The integer N.

* Lines 2…1+N: Line i+1 contains M(i).

输出格式

* Line 1: The number of balanced subsets of cows.

样例 #1

样例输入 #1

4 
1 
2 
3 
4

样例输出 #1

3

提示

There are 4 cows, with milk outputs 1, 2, 3, and 4.

There are three balanced subsets: the subset {1,2,3}, which can be partitioned into {1,2} and {3}, the subset {1,3,4}, which can be partitioned into {1,3} and {4}, and the subset {1,2,3,4} which can be partitioned into {1,4} and {2,3}.

折半搜索、位运算 - AC O2

数据量很小,考虑暴搜。对于一头牛,要么不在这个子集中,要么放进A,要么放进B。时间复杂度 O ( 3 n ) O(3^n) O(3n),超时。

差点就能过了,考虑折半搜索。分成两半,分别搜出所有可能的v=A中产奶量之和-B中产奶量之和。符合条件的是,在两半里各选出一种情况,使得 v 1 + v 2 = 0 v_1+v_2=0 v1+v2=0.
一个子集可能有不同的划分方式,为了防止重复计数,还要记录每种情况使用了哪些牛(位运算)。

折半搜索,先考虑暴搜怎么做,再进行改造。

const int MAXN = 20;

struct Node {
	int v, s;
	Node(int _v, int _s): v(_v), s(_s){}
	bool operator < (const Node &x) const {
		return v < x.v;
	}
};

int n, m[MAXN], ans;
bool vh[1 << MAXN];
vector<Node> v[2];

void dfs(int l, int r, int w, int s, int t) {
	if (l > r) {
		v[t].push_back(Node(w, s));
		return;
	}
	dfs(l + 1, r, w, s, t);
	dfs(l + 1, r, w + m[l], s | (1 << l), t);
	dfs(l + 1, r, w - m[l], s | (1 << l), t);
}

int main() {
	scanf("%d", &n);
	for (int i = 0; i < n; ++i) {
		scanf("%d", m + i);
	}
	
	int mid = (n + 1) >> 1;
	dfs(0, mid - 1, 0, 0, 0);
	dfs(mid, n - 1, 0, 0, 1);
	
	sort(v[0].begin(), v[0].end());
	sort(v[1].begin(), v[1].end());
	for (Node i : v[0]) {
		int j = lower_bound(v[1].begin(), v[1].end(), Node(-i.v, i.s)) - v[1].begin();
		while (j < v[1].size() && v[1][j].v == -i.v) {
			vh[v[1][j++].s | i.s] = true;
		}
	}
	
	for (int i = 1; i < (1 << n); ++i) {
		if (vh[i]) ++ans;
	}
	printf("%d\n", ans);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值