[Usaco2012 Open]Balanced Cow Subsets

题目描述

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

求有多少种选数的方案。

输入输出格式

输入格式:

* 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:

4
1
2
3
4

输出样例#1:

3

题解

这道题算是一个折半搜索(meet in the middle)的好题

如果对折半搜索不太熟悉,可以先做一道较简单的题 [CEOI2015 Day2]世界冰球锦标赛

BZOJ链接洛谷链接 附加my blog

这道题有三种状态

  1. 不放入任何集合
  2. 放入左边集合
  3. 放入右边集合

在搜索时如何表示呢,我们可以0,1,-1来表示,代码如下:

dfs(dep+1,sum);
dfs(dep+1,sum+v[dep]);
dfs(dep+1,sum-v[dep]);

但是我们得到的答案可能会有重复,就是我们可能把一个数选入左集合或右集合,但是都加入了状态,所以我们需要判重。

如何去判重,状态压缩,压成2进制去判重。

所以搜索时还要去记录状态,用一个\(vis\)数组判重。

if(!vis[a[l].state|b[r].state])
vis[a[l].state|b[r].state]=1;//state记录二进制的选数状态 1表示选 0表示没选

最后要统计答案,排序后双指针扫描一遍即可。

注意,最后别忘了把0的那种方案减去。

code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cctype>
#define ll long long
#define R register
#define N 22
using namespace std;
template<typename T>inline void read(T &a){
char c=getchar();T x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
a=f*x;
}
int n,v[N<<1],maxdep,cnta,cntb;
bool vis[1<<N];
ll ans;
struct node{
int state,x;
}a[1<<N],b[1<<N];
inline bool cmp1(R node a,R node b){
return a.x<b.x;
}
inline bool cmp2(R node a,R node b){
return a.x>b.x;
}
inline void dfs(R int dep,R int sum,R int now,R int flg){
if(dep==maxdep+1){
if(!flg){
a[++cnta].x=sum;
a[cnta].state=now;
}
else{
b[++cntb].x=sum;
b[cntb].state=now;
}
return;
}
dfs(dep+1,sum,now,flg);
dfs(dep+1,sum+v[dep],now+(1<<(dep-1)),flg);
dfs(dep+1,sum-v[dep],now+(1<<(dep-1)),flg);
}
int main(){
read(n);
for(R int i=1;i<=n;i++)read(v[i]);
maxdep=n/2;dfs(1,0,0,0);
maxdep=n;dfs(n/2+1,0,0,1);
sort(a+1,a+1+cnta,cmp1);
sort(b+1,b+1+cntb,cmp2);
R int l=1,r=1;
while(l<=cnta&&r<=cntb){
while(-a[l].x<b[r].x&&r<=cntb)r++;
R int pos=r;
while(r<=cntb&&-a[l].x==b[r].x){
if(!vis[a[l].state|b[r].state]){
vis[a[l].state|b[r].state]=1;
ans++;
}
r++;
}
if(l<cnta&&a[l].x==a[l+1].x)r=pos;
l++;
}
printf("%lld\n",ans-1);
return 0;
}

【BZOJ 2679】[Usaco2012 Open]Balanced Cow Subsets(折半搜索+双指针)的更多相关文章

  1. bzoj2679: [Usaco2012 Open]Balanced Cow Subsets(折半搜索)

    2679: [Usaco2012 Open]Balanced Cow Subsets Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 462  Solv ...

  2. 【BZOJ】2679: [Usaco2012 Open]Balanced Cow Subsets

    [算法]折半搜索+数学计数 [题意]给定n个数(n<=20),定义一种方案为选择若干个数,这些数可以分成两个和相等的集合(不同划分方式算一种),求方案数(数字不同即方案不同). [题解] 考虑直 ...

  3. BZOJ_2679_[Usaco2012 Open]Balanced Cow Subsets _meet in middle+双指针

    BZOJ_2679_[Usaco2012 Open]Balanced Cow Subsets _meet in middle+双指针 Description Farmer John's owns N ...

  4. 折半搜索+Hash表+状态压缩 | [Usaco2012 Open]Balanced Cow Subsets | BZOJ 2679 | Luogu SP11469

    题面:SP11469 SUBSET - Balanced Cow Subsets 题解: 对于任意一个数,它要么属于集合A,要么属于集合B,要么不选它.对应以上三种情况设置三个系数1.-1.0,于是将 ...

  5. [Usaco2012 Open]Balanced Cow Subsets

    Description Farmer John's owns N cows (2 <= N <= 20), where cow i produces M(i) units of milk ...

  6. BZOJ2679 : [Usaco2012 Open]Balanced Cow Subsets

    考虑折半搜索,每个数的系数只能是-1,0,1之中的一个,因此可以先通过$O(3^\frac{n}{2})$的搜索分别搜索出两边每个状态的和以及数字的选择情况. 然后将后一半的状态按照和排序,$O(2^ ...

  7. bzoj2679:[Usaco2012 Open]Balanced Cow Subsets

    思路:折半搜索,每个数的状态只有三种:不选.选入集合A.选入集合B,然后就暴搜出其中一半,插入hash表,然后再暴搜另一半,在hash表里查找就好了. #include<iostream> ...

  8. SPOJ-SUBSET Balanced Cow Subsets

    嘟嘟嘟spoj 嘟嘟嘟vjudge 嘟嘟嘟luogu 这个数据范围都能想到是折半搜索. 但具体怎么搜呢? 还得扣着方程模型来想:我们把题中的两个相等的集合分别叫做左边和右边,令序列前一半中放到左边的数 ...

  9. codeforces912E(折半搜索+双指针+二分答案)

    E. Prime Gift E. Prime Gift time limit per test 3.5 seconds memory limit per test 256 megabytes inpu ...

随机推荐

  1. Delphi PDF

    llPDFLib,TPDFDocument 2016开始开源. procedure TForm2.Button1Click(Sender: TObject); var lPdf : TPdfDocum ...

  2. ms project设置行高

    1.取消某列的自动换行右击“任务名称”——自动换行 2.全选所有任务点击左上角单元格 3.设置所有行的行高点击任意行最左边单元格的下边框,向上拖放 4.ok

  3. 模仿慕课网一步步发布一个开源库到 JCenter

    H:\common\-common-25.2.2\upload.gradle // Bintray /* Properties properties = new Properties() proper ...

  4. opennebula 模板参数说明

    两种模板配置方式一.光驱引导启动需要配置:disk1:磁盘类型:cdrom      驱动类型:file      磁盘标记:hd      是否只读:yesDisk2:磁盘类型:DATABLOCK驱 ...

  5. Zephyr Introduction

    wiki Importer Workflow wiki https://zephyrdocs.atlassian.net/wiki/display/ZTD/Zephyr+for+JIRA+Docume ...

  6. while循环for循环优缺点和应用

    while循环常用于那种不知道循环次数是多少的情况,比如让用户循环输入一个整数,直到输入某个特殊的字符为止,你根本没法直到这个循环会进行的次数. for循环多用于循环次数比较明确的情况,比如for(n ...

  7. Django开发——集成的子框架django.contrib

    Django开发——集成的子框架django.contrib 2018年09月11日 19:32:42 Mrkang1314 阅读数:63  https://blog.csdn.net/mashaok ...

  8. 数据结构 Merge合并排序

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. WinAPI多线程

    WIN32线程控制主要实现线程的创建.终止.挂起和恢复等操作,这些操作都依赖于WIN32提供的一组API和具体编译器的C运行时库函数.在启动一个线程之前,必须为线程编写一个全局的线程函数,一般来说,C ...

  10. 黑盒测试实践--Day6 11.30

    黑盒测试实践--Day6 11.30 今天完成任务情况: 应用设计的场景用例,完成测试用例的编写 完成测试用例在自动化测试工具QTP上的测试 分析测试结果得到缺陷报告 小靳 软件测试 今天主要钻研了q ...