BZOJ 2679: [Usaco2012 Open]Balanced Cow Subsets meet_in_the_middle / 折半搜索

2679: [Usaco2012 Open]Balanced Cow Subsets

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 316  Solved: 128
[Submit][Status][Discuss]

Description

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.

给出N1N20)个数M(i) (1 <= M(i) <= 100,000,000)在其中选若干个数,如果这几个数可以分成两个和相等的集合,那么方案数加1。问总方案数。

Input

 Line 1: The integer N. 
 Lines 2..1+N: Line i+1 contains M(i).

Output

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

Sample Input

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

Sample Output

3
OUTPUT DETAILS: 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}.

第一次写折半搜索

就是meet in the middle

每个数的系数只能是-1,0,1,因此可以先通过 O(3n2) 的搜索分别搜索出两边每个状态的和以及数字的选择情况。

然后将后一半的状态按照和排序

O(2n2) 枚举前一半的每一个选择情况的状态,将该选择情况下所有状态按和排序,然后通过双指针求出所有合法状态。

时间复杂度去看zgz233的博客


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>

using namespace std;

typedef double db;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void print(int x)
{if(x>=10)print(x/10);putchar(x%10+'0');} 

const int N=50,M=4100000;

struct node{int sum,st;}x[M],y[M];
inline bool cmp1(const node &a,const node &b)
{return a.sum<b.sum;}
inline bool cmp2(const node &a,const node &b)
{return a.sum>b.sum;}
int cntx,cnty;

int a[N],n;

void dfs(int now,int aim,int sum,int st)
{
	if(now>aim)
	{
		if(aim==n>>1)
		{
			x[++cntx].sum=sum;
			x[cntx].st=st;
		}
		else
		{
			y[++cnty].sum=sum;
			y[cnty].st=st;
		}
		return ;
	} 
	dfs(now+1,aim,sum,st);
	dfs(now+1,aim,sum+a[now],st+(1<<now));
	dfs(now+1,aim,sum-a[now],st+(1<<now));
}

bool vis[M];
int main()
{
	n=read();
	register int i,j,ans;
	for(i=1;i<=n;++i)a[i]=read();
	dfs(1,n>>1,0,0);dfs((n>>1)+1,n,0,0);
	sort(x+1,x+cntx+1,cmp1);sort(y+1,y+cnty+1,cmp2);
	i=j=1,ans=0;
	while(i<=cntx&&j<=cnty)
	{
		while(j<=cnty&&y[j].sum>-x[i].sum)++j;
		int tmp=j;
		while(y[j].sum+x[i].sum==0)
		{
			if(!vis[x[i].st|y[j].st])
			{
				ans++;
				vis[x[i].st|y[j].st]=1;
			}
			j++;
		}
		j=tmp;
		i++;
	}
	print(ans-1);puts("");return 0;
} 
/*
4
1 2 3 4

3
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值