bitset 位容器集合
来源:互联网 发布:cpu风扇转速软件 编辑:程序博客网 时间:2024/05/16 13:04
bitset
bitset容器是一个bit位元素的序列容器,每个元素只占一个bit位,取值为0或1,因而很节省内存空间。它的10个元素只用了两个字节的空间。
头文件:#include<bitset>
bitset类的方法列表:(bitset<N>b)
b.any() : b中是否存在置为1的二进制位?
b.none(): b中不存在置为1的二进制位吗?
b.count(): b中置为1的二进制位的个数
b.size() : b中二进制位的个数
b[pos]: 访问b中在pos处的二进制位
b.test(pos): b中在pos处的二进制是否为1?
b.set(): 把b中所有二进制位都置为1
b.reset(): 把b中所有二进制位都置为0
b.reset(pos): 把b中在pos位的二进制置为0
b.flip(): 把b中所有二进制位逐位取反
b.flip(pos): 把b中在pos位的二进制位取反
b.to_ulong(): 用b中同样的二进制位返回一个unsigned long 值
os<<b: 把b中的位集输出到os流
b<<k: 把b中所有为1的位向高位移k个位置
b>>k: 把b中所有为1的位向低位移k个,自动舍弃超出范围的位
b=(int)n: 用n的二进制位填充b
两个同级bitset对象还可以进行^、&、| 等操作。
bitset的常数很小,进行整体操作的复杂度大概b.size()/64的样子。
1. 创建bitset对象
创建bitset对象时必须要指定容器大小。bitset对象的大小一经定义就不能修改了。
bitset<100>b:定义bitset对象b,能容纳100个比特位(0-99),所有位初始都为0。
2.设置元素值
(1)采用下标法:b[pos]=1。
bitset<5>b;
b[1]=1,b[2]=1,b[4]=1;
输出:01101
(2)采用set()方法,一次性将元素设置为1。
bitset<5>b;
b.set();
输出:11111
(3)采用set(pos,1)方法直接将pos位置为1或者0
bitset<5>b;
b.set(1,1);
b.set(2,1);
b.set(4,1);
输出:01101
(4)采用reset(pos)方法将pos位置为0
bitset<5>b;
b.set(1,1);
b.set(2,1);
b.set(4,1);
b.reset(2);
输出:01001
3.输出元素
(1)采用下标法输出元素
bitset<5>b;
for(int i=0;i<5;i++) cout<<b[i];
for(int i=0;i<b.size();i++) cout<<b[i];
(2)直接向输出流输出所有元素
cout<<b<<endl;
bitset在很多优化技巧上可以用到,是很好用的stl容器。
我自己拉了一个bitset专题练习,对相关知识进行总结一下:
bitset 练习
HDU - 2051
Bitset
题意:输出n个二进制位。
bitset裸题,直接采用上述赋值法,然后从首个不为0的高位到低位输出即可。
int n; bitset<11>b; while(~scanf("%d",&n)) { b=n; int flag=0; for(int i=10;i>=0;i--) { if(b[i]) printf("%d",int(b[i])),flag=1; else if(flag) printf("%d",int(b[i])); } puts(""); }
HDU - 4920
Matrix multiplication
题意:给你两个n*n的矩阵,求矩阵乘积取余3的矩阵。n可达800,时限2s。
直接800^3复杂度5.12e8超时的风险。注意结果对3取余再输出,那么每个初始矩阵的值都只会是0、1、2中的一个。我们可以用3维的bitset表示每一个(i,j)是1还是2,0对大答案无贡献。这样我们普通矩阵相乘是n^3的复杂度,但第三层循环完全可以用bitset优化,对应行和对应列进行&操作再统计有多有个1即知道答案的贡献了。复杂度n^3/64。
int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];bitset<maxn>aa[maxn][2],bb[maxn][2];int main(){ int n; while(~scanf("%d",&n)) { for(int i=0; i<n; i++) for(int j=0; j<n; j++) { aa[i][0].reset(); aa[i][1].reset(); bb[i][0].reset(); bb[i][1].reset(); } for(int i=0; i<n; i++) for(int j=0; j<n; j++) { scanf("%d",&a[i][j]); a[i][j]%=3; if(a[i][j]==1) aa[i][0][j]=1; else if(a[i][j]==2) aa[i][1][j]=1; } for(int i=0; i<n; i++) for(int j=0; j<n; j++) { scanf("%d",&b[i][j]); b[i][j]%=3; if(b[i][j]==1) bb[j][0][i]=1; else if(b[i][j]==2) bb[j][1][i]=1; }// for(int i=0;i<n;i++)// for(int j=0;j<n;j++)// printf("i=%d j=%d aa0=%d bb0=%d aa1=%d bb1=%d\n",i,j,int(aa[i][0][j]),int(bb[j][0][i]),int(aa[i][1][j]),int(bb[j][1][i])); for(int i=0; i<n; i++) for(int j=0; j<n; j++) c[i][j]=(2*(aa[i][1]&bb[j][0]).count()+2*(aa[i][0]&bb[j][1]).count()+(aa[i][0]&bb[j][0]).count()+4*(aa[i][1]&bb[j][1]).count())%3; for(int i=0; i<n; i++) for(int j=0; j<n; j++) printf("%d%c",c[i][j],j==n-1?'\n':' '); } return 0;}
POJ - 2443
Set Operation
题意:有n个集合,每个集合k个数,Q次查询,每次查询是否存在一个集合同时包含查询的两个数。
每一位表示一个集合,这一位对应的数在哪个集合中出现过就将对应位置为,查询两个数只需将这个两个数位对应的集合进行&后统计1的个数是否为0即可。
const int N=1e4+5;const int maxn=800+5;bitset<1001>b[N];int main(){ int n,q,k,p; while(~scanf("%d",&n)) { for(int i=0;i<N;i++) b[i].reset(); for(int i=0;i<n;i++) { scanf("%d",&k); while(k--) { scanf("%d",&p); b[p][i]=1; } } scanf("%d",&q); while(q--) { scanf("%d%d",&k,&p); if((b[k]&b[p]).count()) puts("Yes"); else puts("No"); } } return 0;}
HDU - 5036
Explosion
题意:魔塔都玩过吧,每个房间里都有一些钥匙,能打开对应的门,当没有钥匙能开门后只能用一颗炸弹炸开一扇门,求打开所有门需要炸弹数量的期望。
期望等于值乘以概率,值当然为1了,概率即能够通往这个门的数量的倒数。累加求和就是ans。那就得求出打开哪些门才能打开这扇门,这就是一个传递闭包的过程,用bitset优化
const int N=1e3+5;const int maxn=800+5;bitset<N>b[N];int t,n,k,p;void init(){ scanf("%d",&n); for(int i=1; i<=n; i++) b[i].reset(); for(int i=1; i<=n; i++) { scanf("%d",&k); while(k--) { scanf("%d",&p); b[i][p]=1; } b[i][i]=1; } for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if(b[j][i]) b[j]|=b[i];}int main(){ scanf("%d",&t); int t1=t; while(t--) { init(); double ans=0.0; for(int i=1; i<=n; i++) { double num=0; for(int j=1; j<=n; j++) if(b[j][i]) num+=1; ans+=1.0/num; } printf("Case #%d: %.5f\n",t1-t,ans); } return 0;}
HDU - 5313
Bipartite Graph
题意:给你n个点,m条边,求最多能加多少边使得这n个点变成一个完全二分图。
什么是完全二分图呢,就是两个集合中的点都互相连边了。先来看一个不等式:ab<=((a+b)^2)/2当且仅当a==b取等。于是我们可以二分图染色将原有边分成的两部分求出来,剩下的就相当于选一些集合合并,合并后的集合的点数和剩下的点数的差值最小。可以用背包优化,但bitset会更优一点,代码写好写好理解。如果用背包,那么背包容量应该设为n/2。但bitset可以直接左移或者右移表示所有数同时加上或减去一个数,我们求出所有组合然后枚举最优解即可。具体怎么求出所有组合看代码:
这个优化可以改变很多题的,很多01背包就可以用这个优化解:比如NYOJ:邮票分你一半、zb的生日。
const int N=1e4+10;bitset<N>cur;struct Edge{ int to,next;} e[N*20];struct Node{ int a,b;} node[N];int head[N],tot,flag[N];void init(){ tot=0; memset(flag,0,sizeof(flag)); memset(head,-1,sizeof(head)); cur.reset(); cur.set(0);}void add(int u,int v){ e[tot].to=v,e[tot].next=head[u]; head[u]=tot++; e[tot].to=u,e[tot].next=head[v]; head[v]=tot++;}void dfs(int &a,int &b, int u,int f){ flag[u]=1; if(f) a++; else b++; for(int i=head[u]; i+1; i=e[i].next) { int v=e[i].to; if(flag[v]) continue; dfs(a,b,v,f^1); }}int main(){ int t,n,m; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); int u,v,k=0; for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); add(u,v); } for(int i=1; i<=n; i++) if(!flag[i]) { int a=0,b=0; dfs(a,b,i,1); node[k].a=a,node[k++].b=b; } for(int i=0; i<k; i++) cur=(cur<<node[i].a)|(cur<<node[i].b); int ans=0; for(int i=1; i<=n; i++) if(cur[i]) ans=max(ans,(n-i)*i-m); printf("%d\n",ans); } return 0;}
HDU - 6085
Rikka with Candies
今年多校的新题,正解应该是手写压位,但优化好的bitset也可以卡过,题意和思路就不详细介绍了。
- Bitset位集合容器
- bitset位集合容器
- bitset 位容器集合
- C++STL之bitset位集合容器
- c++stl的bitset位集合容器
- STL泛型编程-bitset位集合容器
- ACM学习历程17——bitset位集合容器
- STL之bitset位集合
- [C++ 从入门到放弃-10]C++STL之bitset位集合容器
- 位向量实现的bitset集合
- STL容器之 bitset
- C++中的bitset容器
- STL容器之bitset
- STL容器之bitset
- BitSet(置位) 示例
- BitSet位操作
- 位操作与BitSet
- Bitset(位组)
- 自动化测试—Selenium RC配置相关
- ios cookie的使用
- C#学习-BackgroundWorker控件和ProgressBar控件使用
- Java+Selenium3.3.1环境搭建
- python对函数库引用的方式
- bitset 位容器集合
- JavaScript模拟oop语言实现类的创建
- caffe 学习笔记-模型训练与测试
- 概率基础3-随机变量与分布函数
- PADS中过孔尺寸与设置值不一致的问题
- node核心模块之读取文件
- JMX RMI简介
- ceph
- react-navigation 使用详解