【JZOJ4841】【NOIP2016提高A组集训第4场11.1】平衡的子集
题目描述
夏令营有N个人,每个人的力气为M(i)。请大家从这N个人中选出若干人,如果这些人可以分成两组且两组力气之和完全相等,则称为一个合法的选法,问有多少种合法的选法?
数据范围
40%的数据满足:1<=M(i)<=1000;
对于100%的数据满足:2<=N<=20,1<=M(i)<=100000000
解法
40%
枚举每一位选或不选,设当前选的所有数的和为sum,然后使用背包求出当前每个可能的总和。
如果其中有sum/2,那么说明这种选法合法,使答案+1;
100%
比较显然的暴力是O(320)。
现在考虑使用折半搜索;
将原数集分为两个均匀的集合,
分别搜索出两个集合中所有可能的和,O(2∗310);
由于一个集合中的负系数相当于把这项移项到另一个集合中。
所以直接找出两个集合中可能的和相等的数量即可。
运用二进制记录每个和选的方案,来防止重复计数。
实现:
将两组和排序,设l为第一组的指针,r为第二组的指针;
通过此大彼进,使得a[l]==b[r];
相同的和之间两两匹配来贡献答案,判重。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
const char* fin="subset.in";
const char* fout="subset.out";
const int maxn=50,maxh=1048580;
const int er[21]={1,2,4,8,16,32,64,128,256,512,1024};
int n,nn,i,j,k;
int a[maxn],b[maxn];
bool bz[1025][1025];
int h[maxh];
int ans1;
int fi[maxh],ne[maxh],la[maxh],en[maxh];
int ans,tot,tot1;
int ans2;
void add_line(int a,int b,int c){
if (h[a]<0){
tot++;
fi[a]=en[a]=tot;
la[tot]=b;
h[a]=c;
}else{
ne[en[a]]=tot+1;
tot++;
en[a]=tot;
la[tot]=b;
}
}
int hash(int v){
int k=(v%maxh+maxh)%maxh;
while (h[k]!=ans1 && h[k]!=v) {
k=(k+1)%maxh;
}
return k;
}
void dfs(int v,int sum,int state){
int i,j,k;
if (v>nn){
k=hash(sum);
add_line(k,state,sum);
return ;
}
dfs(v+1,sum,state);
dfs(v+1,sum+a[v],state+er[v-1]);
dfs(v+1,sum-a[v],state+er[v-1]);
}
void getans(int v,int sum,int stat){
int i,j,k;
if (v>n){
k=hash(sum);
if (h[k]!=ans1){
if (fi[k]==ans1) return;
ans2++;
j=0;
for (i=fi[k];i;i=ne[i]){
j++;
if (!bz[stat][la[i]]){
ans++;
bz[stat][la[i]]=true;
}
}
//ans2=ans2+j;
}
return;
}
getans(v+1,sum,stat);
getans(v+1,sum+a[v],stat+er[v-1-nn]);
getans(v+1,sum-a[v],stat+er[v-nn-1]);
}
int main(){
freopen(fin,"r",stdin);
freopen(fout,"w",stdout);
scanf("%d",&n);
nn=n/2;
memset(h,128,sizeof(h));
memset(fi,128,sizeof(fi));
ans1=h[0];
for (i=1;i<=n;i++) scanf("%d",&a[i]);
dfs(1,0,0);
getans(nn+1,0,0);
ans--;
printf("%d",ans);
return 0;
}
启发
折半搜索
本题
本题:每个数有不选,隶属A,隶属B,三种选择。
而对于在一个集合中,每个数的选择意义就是不选,隶属这个集合①,隶属另一个集合②。
①②选择在两个集合之间互逆。
姑且称这些元素的抉择是奇性的。
那么本体就可以使用折半搜索。
拓展
现在有这么一题,
夏令营有N个人,每个人的力气为M(i)。问有多少种分法将这N个人分成两组且两组力气之和完全相等?(n<=40,m(i)<=10000000)
暂且不考虑其他玄学算法,考虑折半搜索:
直接的想法是O(2n)搜索,这显然超时;
但每个项的两个抉择互逆,也就是说每个项的抉择呈奇性。
将原数集分为两个均匀的集合。
分别使用O(2n/2)处理出两个集合的所有可能的和。
然后合并答案即可,使用二进制判重。
上述脑洞题算是与原问题的一个“外传”,也是应用折半搜索。
总结
大概折半搜索需要这个条件,将原数集分成两个均匀的集合后,项的抉择呈奇性。
至于奇性是什么上文已感性阐述,属博主自创词汇。
【JZOJ4841】【NOIP2016提高A组集训第4场11.1】平衡的子集的更多相关文章
- JZOJ 【NOIP2016提高A组集训第16场11.15】兔子
JZOJ [NOIP2016提高A组集训第16场11.15]兔子 题目 Description 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3 ...
- JZOJ 【NOIP2016提高A组集训第16场11.15】SJR的直线
JZOJ [NOIP2016提高A组集训第16场11.15]SJR的直线 题目 Description Input Output Sample Input 6 0 1 0 -5 3 0 -5 -2 2 ...
- 【NOIP2016提高A组集训第4场11.1】平衡的子集
题目 夏令营有N个人,每个人的力气为M(i).请大家从这N个人中选出若干人,如果这些人可以分成两组且两组力气之和完全相等,则称为一个合法的选法,问有多少种合法的选法? 分析 如果暴力枚举每个人被分到哪 ...
- 【NOIP2016提高A组集训第14场11.12】随机游走
题目 YJC最近在学习图的有关知识.今天,他遇到了这么一个概念:随机游走.随机游走指每次从相邻的点中随机选一个走过去,重复这样的过程若干次.YJC很聪明,他很快就学会了怎么跑随机游走.为了检验自己是不 ...
- 【NOIP2016提高A组集训第13场11.11】最大匹配
题目 mhy12345学习了二分图匹配,二分图是一种特殊的图,其中的点可以分到两个集合中,使得相同的集合中的点两两没有连边. 图的"匹配"是指这个图的一个边集,里面的边两两不存在公 ...
- 【NOIP2016提高A组集训第14场11.12】随机游走——期望+树形DP
好久没有写过题解了--现在感觉以前的题解弱爆了,还有这么多访问量-- 没有考虑别人的感受,没有放描述.代码,题解也写得歪歪扭扭. 并且我要强烈谴责某些写题解的代码不打注释的人,像天书那样,不是写给普通 ...
- 【JZOJ4901】【NOIP2016提高A组集训第18场11.17】矩阵
题目描述 他是一名普通的农电工,他以一颗无私奉献的爱岗敬业之心,刻苦钻研业务,以娴熟的技术.热情周到的服务赢得了广大客户的尊敬和赞美.他就是老百姓称为"李电"的李春来. 众所周知, ...
- 【JZOJ4898】【NOIP2016提高A组集训第17场11.16】人生的价值
题目描述 NiroBC终于找到了人生的意义,可是她已经老了,在新世界,没有人认识她,她孤独地在病榻上回顾着自己平凡的一生,老泪纵横.NiroBC多么渴望再多活一会儿啊! 突然一个戴着黑色方框眼镜,方脸 ...
- 【JZOJ4899】【NOIP2016提高A组集训第17场11.16】雪之国度
题目描述 雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路.雪之女王赋予了每一座城市不同的能量,其中第i座城 ...
随机推荐
- Maven实战01_Maven简介
1:何为Maven Maven:中文翻译为"知识的积累",也可翻译为"专家"或"内行". 谈到Maven,就不得不提"构建(bui ...
- VS2010中Cocos2d-x中文乱码问题
不罗嗦,直接进入主题,VS2010的默认编码是"GB2312",那么以创建一个label为例,当我们使用 CCLabelTTF::create(const char *label, ...
- LeetCode简单算法之分割平衡字符串 #1221
在一个「平衡字符串」中,'L' 和 'R' 字符的数量是相同的. 给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串. 返回可以通过分割得到的平衡字符串的最大数量. 示例 1: 输入:s = ...
- ubuntu下编译安装poco
系统环境: ubuntu版本:Linux jfcai-VirtualBox 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 ...
- pytest框架-介绍、Mark(打标签)、命令运行用例、用例执行顺序、
1.pytest介绍:基于unittest 之上的单元测试框架 1.1.自动发现测试模块和测试用例: unitest 需要添加用例,(泰斯特楼贷)加载器加载测试用例 pytest 只需要一条代码就可以 ...
- Python学习之高阶函数--嵌套函数、函数装饰器、含参函数装饰器
玩了一晚上王者,突然觉得该学习,然后大晚上的搞出来这道练习题,凌晨一点写博客(之所以这么晚就赶忙写是因为怕第二天看自己程序都忘了咋写的了),我太难了o(╥﹏╥)o 言归正传,练习题要求:构造类似京东的 ...
- 使用video.js支持flv格式
html5的video标签只支持mp4.webm.ogg三种格式,不支持flv格式,在使用video.js时,如果使用html5是会报错不支持. 修改了一下代码 js部分 videojs.option ...
- 警告: [SetPropertiesRule]{Context/Loader} Setting property 'useSystemClassLoaderAsParent' to 'false' did not find a matching property.
警告: [SetPropertiesRule]{Context/Loader} Setting property 'useSystemClassLoaderAsParent' to 'false' d ...
- Wsgi研究
//转载自http://blog.kenshinx.me/blog/wsgi-research/ wsgi是一个搞web开发的pythoner必须了解的内容,之前也零散的看过一些文章,但总感觉好多概念 ...
- (2)卷积 & 卷积和
参考资料:<信号与系统(第二版)> 杨晓非 何丰 连续信号的是卷积积分,离散信号的是卷积和. 脉冲分量 任意非周期信号,将横坐标分为若干个微小等分,得到Δτ为宽,f(kΔτ)为高的一系列微 ...