【JZOJ4841】平衡的子集
2016-12-09 19:26
204 查看
Description
有N个人,每个人的力气为M(i)。从这N个人中选出若干人,如果这些人可以分成两组且两组力气之和完全相等,则称为一个合法的选法,问有多少种合法的选法?请注意这里是选人的方案而不是分组的方案。
Solution
我们考虑暴力,时间复杂度O(320),显然不能接受。我们假设分进某一组权wi为-1或1,不选为0,那么每个人和的贡献就是wiMi。
于是我们可以先搜索前面一半的元素,然后我们知道跨越两边的选法左边和右边的贡献和为0,凭借此我们就可以在搜索后面一半元素的时候顺便统计选法跨越中间的方案数,然后判重即可。
对于判重的理解:由于我们统计的是选人的方案,所以可能某一种选法的不同两种分组方法的贡献相等,然而其中一个是没有用的。
那么有了这个有什么用呢?这首先保证你答案不会多,其次在加进状态时若发现贡献一样,选法相同的分配的状态可以不用记录。
Code
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,j,k) for(int i=j;i<=k;i++) #define fd(i,j,k) for(int i=j;i>=k;i--) #define rep(i,x) for(int i=ls[x];i;i=nx[i]) #define MAX 22 #define M 1048577 #define S 1025 #define NN 44 using namespace std; int Z,N,n; int a[MAX],h[M],er[MAX]; int ans=0; bool bz[S][S]; int nx[M],ls[M],to[M],num=0; int hash(int x) { int p=(x%M+M)%M; while(h[p]!=Z && h[p]!=x) p=(p+1)%M; return p; } void link(int x,int y) { num++; to[num]=y; nx[num]=ls[x]; ls[x]=num; } void dfs(int x,int s,int st) { if(x>n) { int t=hash(s); h[t]=s; bool tf=true; rep(i,t) { int v=to[i]; if(v==st) { tf=false; break; } } if(tf) link(t,st); return; } fo(i,-1,1) { int p=st; if(i) p+=er[x-1]; dfs(x+1,s+a[x]*i,p); } } void get(int x,int s,int st) { if(x>N) { int t=hash(-s); if(h[t]==Z) return; rep(i,t) { int v=to[i]; if(!bz[st][v]) { bz[st][v]=true; ans++; } } return; } fo(i,-1,1) { int p=st; if(i) p+=er[x-n-1]; get(x+1,s+a[x]*i,p); } } int main() { freopen("subset.in","r",stdin); freopen("subset.out","w",stdout); scanf("%d",&N); n=N/2; fo(i,1,N) scanf("%d",&a[i]); memset(h,128,sizeof(h)); Z=h[1]; er[0]=1; fo(i,1,MAX-1) er[i]=er[i-1]*2; dfs(1,0,0); get(n+1,0,0); printf("%d",ans-1); }
相关文章推荐
- 【jzoj4841】【平衡的子集】【搜索】
- 【JZOJ4841】【NOIP2016提高A组集训第4场11.1】平衡的子集
- jzoj4841 平衡的子集
- [JZOJ4841] 平衡的子集
- Jzoj4841 平衡的子集
- 【JZOJ 4841】平衡的子集
- {题解}[jzoj4841]【NOIP2016提高A组集训第4场11.1】平衡的子集
- 【JZOJ 4841】平衡的子集 口胡题解
- JZOJ4841 平衡的子集
- 【NOIP2016提高A组集训第4场11.1】平衡的子集
- JZOJ 4841【NOIP2016提高A组集训第4场】平衡的子集
- 【NOIP2016提高A组集训第4场11.1】平衡的子集
- 平衡的子集 【NOIP2016提高A组集训第4场11.1】
- 二进制枚举子集
- 平衡查找树之2-3树
- UVA131德州扑克之枚举子集
- 求一个集合的所有子集
- 非递归学习树结构(五)--AVL(自平衡二叉排序)树
- 打印字符串所有的子集
- 动态姿态平衡分析