BZOJ

洛谷

\(Description\)

给定\(n\)个数\(A_i\)。求它有多少个子集,满足能被划分为两个和相等的集合。

\(n\leq 20,1\leq A_i\leq10^8\)。

\(Solution\)

显然我们要预处理哪些集合可以被划分为两个和相等的集合。每个元素三种状态,这样我们就可以得到一个\(O(3^n)\)的做法。。

显然不行啊,但是和相等这种东西可以折半啊!

将序列分成两半分开DFS。这样两个和相等的集合\(S_1,S_2\)中的元素可能会被分开。设\(a\)为\(S_1\)在前一半中序列的元素的和,\(b\)为\(S_1\)在后一半序列中的元素的和;\(c,d\)分别为\(S_2\)在前一半/后一半序列中元素的和。那么有\(a+b=c+d\to a-c=d-b\)。所以我们统计两半序列中哪些\(a-c\)相等的集合就可以了。

和为\(a-c\)的集合可能有多个,直接\(Hash/map+vector\)存一下有哪些集合就可以了(这题集合可以直接二进制状压)。

复杂度是不是还会被卡到\(O(6^{\frac n2})\)啊。。在SPOJ是T了,但能过BZOJ。

其实合并状态可以sort后线性合并,就快很多并且能过了。(不对啊,感觉复杂度差不多啊==,我hash写太丑了?)

当然这也不是正解,还有更快的,比如:https://blog.csdn.net/u014609452/article/details/51872702

//7132kb	2584ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod 20000000
typedef long long LL;
const int N=61005;//为啥60005在BZOJ上RE啊,自测可过。 int n,mid,cnt,A[23],Enum,H[(1<<20)+5],sum[N],nxt[N];
bool vis[(1<<20)+5];
struct Node
{
int s,sum;
bool operator <(const Node &x)const
{
return sum<x.sum;
}
}rs[N]; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AE(int s,int Sum)
{
sum[++Enum]=Sum, nxt[Enum]=H[s], H[s]=Enum;
}
void DFS1(int x,int s,int sum)
{
if(x<0) {AE(s,sum); return;}
DFS1(x-1,s,sum), DFS1(x-1,s|(1<<x),sum+A[x]), DFS1(x-1,s|(1<<x),sum-A[x]);
}
void DFS2(int x,int s,int sum)
{
if(x==n) {rs[++cnt]=(Node){s,sum}; return;}
DFS2(x+1,s,sum), DFS2(x+1,s|(1<<x),sum+A[x]), DFS2(x+1,s|(1<<x),sum-A[x]);
} int main()
{
static int lsum[N];
n=read(),mid=n>>1;
for(int i=0; i<n; ++i) A[i]=read();
DFS1(mid-1,0,0), DFS2(mid,0,0);
std::sort(rs+1,rs+1+cnt);
for(int s=0,l=1<<mid; s<l; ++s)
{
int t=0;
for(int i=H[s]; i; i=nxt[i]) lsum[++t]=sum[i];
std::sort(lsum+1,lsum+1+t);
for(int i=1,now=1; i<=cnt; ++i)
{
while(now<=t && lsum[now]<rs[i].sum) ++now;
if(now>t) break;
if(lsum[now]==rs[i].sum) vis[rs[i].s|s]=1;
}
}
int ans=0;
for(int i=1,l=1<<n; i<l; ++i) ans+=vis[i];//同一个集合会算重啊
printf("%d\n",ans); return 0;
}

在SPOJ上T掉的:

//89344kb	7060ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod 20000000
typedef long long LL;
const int N=61005; int n,mid,A[23];
bool vis[(1<<20)+5];
struct Hash_Table
{
int delta,Enum,H[mod+2],nxt[N],s[N]; LL sum[N];//可能冲突 再存一下sum
inline void Insert(int S,LL Sum)
{//注意和可能是负的(加一个mod不就好了==)
int x=(Sum+delta)%mod;
s[++Enum]=S, sum[Enum]=Sum, nxt[Enum]=H[x], H[x]=Enum;
}
inline void Solve(int S,LL Sum)
{
int x=(Sum+delta)%mod;
for(int i=H[x]; i; i=nxt[i])
if(sum[i]==Sum) vis[S|s[i]]=1;
}
}hs; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void DFS1(int x,int s,LL sum)
{
if(x==mid) {hs.Insert(s,sum); return;}
DFS1(x+1,s,sum), DFS1(x+1,s|(1<<x),sum+A[x]), DFS1(x+1,s|(1<<x),sum-A[x]);
}
void DFS2(int x,int s,LL sum)
{
if(x==n) {hs.Solve(s,sum); return;}
DFS2(x+1,s,sum), DFS2(x+1,s|(1<<x),sum+A[x]), DFS2(x+1,s|(1<<x),sum-A[x]);
} int main()
{
n=read(),mid=n>>1; int s=0;
for(int i=0; i<n; ++i) s+=A[i]=read();
hs.delta=s, DFS1(0,0,0), DFS2(mid,0,0);
int ans=0;
for(int i=1,l=1<<n; i<l; ++i) ans+=vis[i];//同一个集合会算重啊
printf("%d\n",ans); return 0;
}

BZOJ.2679.Balanced Cow Subsets(meet in the middle)的更多相关文章

  1. 【BZOJ 2679】[Usaco2012 Open]Balanced Cow Subsets(折半搜索+双指针)

    [Usaco2012 Open]Balanced Cow Subsets 题目描述 给出\(N(1≤N≤20)\)个数\(M(i) (1 <= M(i) <= 100,000,000)\) ...

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

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

  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. bzoj2679: [Usaco2012 Open]Balanced Cow Subsets(折半搜索)

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

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

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

  6. [Usaco2012 Open]Balanced Cow Subsets

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

  7. BZOJ2679 : [Usaco2012 Open]Balanced Cow Subsets

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

  8. bzoj2679:[Usaco2012 Open]Balanced Cow Subsets

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

  9. SPOJ-SUBSET Balanced Cow Subsets

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

随机推荐

  1. stylus入门教程,在webstorm中配置stylus

    转载:https://www.cnblogs.com/wenqiangit/p/9717715.html#undefined   stylus特点 富于表现力.具有健壮性.功能丰富.动态编码 不需要写 ...

  2. 步步为营-74-Request,Response和server的其他成员

    Request 1 Request.UrlReferrer 获取请求的来源 2 Request.UserHostAddress 获取访问者的IP地址 3 Request.Cookies 获取浏览器发送 ...

  3. C#线性表

    线性表是线性结构的抽象 线性结构的特点是结构中的数据元素之间存在一对一的线性关系 一对一的关系指的是数据元素之间的位置关系 (1)除第一个位置的数据元素外,其它数据元素位置的前面都只有一个数据元素 ( ...

  4. [转] mongoose学习笔记(超详细)

    名词解释 Schema: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力 Model: 由Schema编译而成的假想(fancy)构造器,具有抽象属性和行为.Model的每一个实例(ins ...

  5. Redis-Sentinel 哨兵

    为什么需要哨兵? 一旦主节点宕机,那么需要人为修改所有应用方的主节点地址(改为新的master地址),还需要命令所有从节点复制新的主节点 那么这个问题,redis-sentinel就可以解决了 什么是 ...

  6. P3403 跳楼机

    题解: 据说是最短路经典题 考虑mod c一意义下 我们会发现mod c相同的话我们一定会用最少步数到达,剩余的都用c转移 由于转移图有环所以我们用spfa来dp(其实也可以理解成最短路) wa了好多 ...

  7. Rookey.Frame企业级极速开发框架

    项目详细介绍 Rookey.Frame是一套基于.NET MVC + easyui的企业级极速开发框架,支持简单逻辑模块零代码编程.支持工作流(BPM).支持二次开发,具有高扩展性.高复用性.高伸缩性 ...

  8. 如何在grails2.3.x中的fork模式下进行调试?-【grails】

    grails2.3.x中默认情况下运行模式被设置成了fork模式,在这种模式下,大家会发现设置了断点后无法进行中断.这是由于fork模式造成的,因为在fork模式下,JVM新起了一个进程,这样调试器就 ...

  9. day84-仿照admin实现一个自定义的增删改查组件

    一.admin的使用 app01的admin.py文件: class BookConfig(admin.ModelAdmin): list_display=[] list_display_links= ...

  10. 如何禁止某个linux用户访问某些文件夹及执行某些命令

    方案1: 给这个文件A增加个a的隐藏属性,只能增加数据不能删除修改数据,只有root能设置这个隐藏属性 chattr +a A lsattr A 可以查看隐藏属性 方案2: 修改文件所属用户和组,普通 ...