奶牛合作 对于位操作的敏感
2013-07-12 08:23
204 查看
有n( <= 50)头奶牛,每头奶牛都有一个编号(<1048576),把他们分成警察和小偷两队(不能有一队为空),如果两队的合作指数相同,那么就是合法的方案(合作指数是指该队成员的编号进行and操作的结果)(限时2000ms)。
首先比较敏感的就是编号不算大,是2的20次方,还有就是and操作的结果只和0的个数有关系,如果某位有一个0,那么结果必然是0。所以对每一位进行考虑(指的是将数字转成二进制的某位):
假如有4有奶牛,编号依次为1、2、3、4:
位 3 2 1
1 0 0 1 //最左边的0称为第三位,中间的0为第二位,1是第一位
2 0 1 0
3 0 1 1
4 1 0 0
方式一: 奶牛1和奶牛2扮演警察,奶牛3和奶牛4扮演小偷。
方式二: 奶牛1和奶牛2扮演小偷,奶牛3和奶牛4扮演警察。
有四种情况:
1.若每头奶牛该位都是0,那么无论怎么分配,结果的这一位还是0。
2.若每头奶牛该位都是1,那么无论怎么分配,结果的这一位还是1。
3.如果有且只有一头奶牛该位是0,那么结果就是一队是0,一队是1。是无解的。
4.如果有两头以上的(包括两头)奶牛该位是0,只要不把他们都安放在同一个队伍就是合法的。
那么就可以用容斥原理算出不合法的方案数。从每一位进行考虑,将所有该位为0的奶牛都在同一个队伍的情况减去。
有点超时,我是用并查集来寻找0的连通块。
首先比较敏感的就是编号不算大,是2的20次方,还有就是and操作的结果只和0的个数有关系,如果某位有一个0,那么结果必然是0。所以对每一位进行考虑(指的是将数字转成二进制的某位):
假如有4有奶牛,编号依次为1、2、3、4:
位 3 2 1
1 0 0 1 //最左边的0称为第三位,中间的0为第二位,1是第一位
2 0 1 0
3 0 1 1
4 1 0 0
方式一: 奶牛1和奶牛2扮演警察,奶牛3和奶牛4扮演小偷。
方式二: 奶牛1和奶牛2扮演小偷,奶牛3和奶牛4扮演警察。
有四种情况:
1.若每头奶牛该位都是0,那么无论怎么分配,结果的这一位还是0。
2.若每头奶牛该位都是1,那么无论怎么分配,结果的这一位还是1。
3.如果有且只有一头奶牛该位是0,那么结果就是一队是0,一队是1。是无解的。
4.如果有两头以上的(包括两头)奶牛该位是0,只要不把他们都安放在同一个队伍就是合法的。
那么就可以用容斥原理算出不合法的方案数。从每一位进行考虑,将所有该位为0的奶牛都在同一个队伍的情况减去。
有点超时,我是用并查集来寻找0的连通块。
//#define watch #include <cstdio> using namespace std; typedef long long LL; const int N = 50, M = 20; int n, father[M]; bool vis[M]; LL d[M]; inline int getfather(int k) { if (father[k] == k) return k; return father[k] = getfather(father[k]); } int main() { freopen("role.in", "r", stdin); freopen("role.out", "w", stdout); scanf("%d\n", &n); for (int i = 0; i < n; i ++) { int a; scanf("%d", &a); for (int j = 0; j < M; j ++) if ((a >> j & 1) == 0) d[j] |= 1LL << i; } int cant = 0; for (int i = 0; i < M; i ++) { int cnt = 0; for (int j = 0; j < n; j ++) if (d[i] >> j & 1) cnt ++; if (cnt == n || cnt == 0) cant |= 1 << i; else if (cnt == 1) { printf("0\n"); return 0; } } LL ans = (1LL << n) - 2LL; int setn = 1 << M; for (int set = 1; set < setn; set ++) { if (set & cant) continue; bool isplus = true; LL tot = 0LL; for (int i = 0; i < M; i ++) if (set >> i & 1) { vis[i] = false; father[i] = i; isplus = !isplus; tot |= d[i]; for (int j = 0; j < i; j ++) if ((set >> j & 1) && (d[i] & d[j])) father[getfather(i)] = getfather(j); } int cnt = 0; for (int i = 0; i < M; i ++) if ((set >> i & 1) && (! vis[getfather(i)])) { vis[father[i]] = true; cnt ++; } for (int i = 0; i < n; i ++) if ((tot >> i & 1LL) == 0) cnt ++; LL t = (1LL << cnt) - 2LL; #ifdef watch printf("set:%d isplus:%s val:%I64d\n", set, isplus?"true ":"false", t); #endif if (isplus) ans += t; else ans -= t; } printf("%I64d\n", ans); return 0; }
相关文章推荐
- 码农对于开发中敏感配置信息的安全把控
- 一个合作良好的团队里,对于团队成员来说重要的不是垄断技术,而是分享技术的同时做到比其他成员的技术好,做领跑者,而不是垄断者。
- 对于Nexus 7的合作 华硕和Google高层想说啥?
- 对于移动通信三网合作开发计费SDK的一点想法
- 基于汉堡包方法对于两人合作的看法
- php7.0对于敏感词扩展库的兼容
- window cmd命令行中对于空格是敏感的
- 对于敏感词汇的检查
- 对于网上合作学习计划的整理
- 字典树的基础,以及在实际项目中对于敏感词的替换的应用
- 一直对于字节,位数不是太敏感,转载一篇写的很明了的
- CentOS6里面ifcfg-eth0对于大小写敏感
- 对于登陆等敏感信息,我们很多时候不希望浏览器记住账号或者密码
- 对于规则引擎技术的思考
- (Extjs)对于GridPanel的各种操作
- 关于java按位操作运算
- 对于摄像机采集交错视频来说,偶场和奇场是并非由同一帧分拆得来
- 对于微软推出的.NET的理解
- 对于java用发送http请求,请求内容为xml格式
- [阿里笔试]对于192.168.0.0到192.168.0.255这个网络来说,以下说法中正确的是____。