stl大法好之bitset

本文深入探讨了C++标准模板库中的bitset组件,通过示例代码详细解释了bitset的各种操作,包括创建、位运算、位移等。并提供了一个实战应用案例,展示了如何在洛谷P3674题目中利用bitset解决复杂查询问题。

今天考试的时候有一道用bitset的题目…
litble不会bitset…
按照以往的惯例,学习一个stl就是要打一段测试代码:

#include<bits/stdc++.h>
using namespace std;
#define RI register int
int main()
{
	bitset<10> a(string("0011010"));//建立一个大小为10的bitset
	cout<<a<<endl;//0000011010
	bitset<10> b(string("100100110"));
	cout<<b<<endl;//0100100110
	cout<<(a&b)<<endl;//0000000010
	cout<<(a|b)<<endl;//0100111110
	cout<<(a^b)<<endl;//0100111100
	cout<<(a<<1)<<endl;//0000110100
	cout<<(a>>1)<<endl;//0000001101
	cout<<(a.size())<<endl;//返回bitset的位数:10
	cout<<(a.count())<<endl;//返回1的个数:3
	cout<<(a.any())<<endl;//返回是否有1:1
	cout<<(a.none())<<endl;//返回是否无1:0
	a.set();cout<<a<<endl;//全部变成1:1111111111
	a.reset();cout<<a<<endl;//全部变成0:0000000000
	a.set(3);cout<<a<<endl;//将第3位(从0开始计算)变成1:0000001000
	a.reset(3);cout<<a<<endl;//将第3为变成0:0000000000
	b.flip();cout<<b<<endl;//将b全部取反:1011011001
	b.flip(2);cout<<b<<endl;//将第2位取反:1011011101
	b[9]=0;cout<<b<<endl;//访问第9位:0011011101
	unsigned int orz=b.to_ulong();//将bitset转化成usigned int
	cout<<orz<<endl;//221
	return 0;
}

使用bitset的时空复杂度大约是 O ( n 32 ) O(\frac{n}{32}) O(32n)的,因为它的基本原理是每32个连续的数字压成一个int。
当然如果你觉得bitset常数太大,可以试试某Cai佬的方法:手写bitset,还可以用long long压
按照以往的惯例,学一个stl就要用这个stl水一道题…
选择洛谷P3674
莫队,并维护两个bitset,一个叫orz存数x是否存在,一个叫cai存数N-x(N是一个大数)是否存在。
然后对于第一个询问,就是看是否存在a-b=x即a=x+b。所以直接查(orz&(orz<<x)).any()即可。
第二个询问,看是否存在a+b=x即N-b+x-N=a,查(orz&(cai>>(BIG-x))).any()
第三个询问,枚举较小的约数。

#include<bits/stdc++.h>
using namespace std;
int read() {
	int q=0;char ch=' ';
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
	return q;
}
#define RI register int
const int N=100005,BIG=100000;
int n,m,sqn;
int a[N],pos[N],js[N],ans[N];
bitset<N> orz,cai;
struct node{int op,l,r,x,id;}q[N];
bool cmp(node a,node b) {return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;}
void add(RI x,RI num) {
	if(js[x]==0&&num==1) orz[x]=1,cai[BIG-x]=1;
	if(js[x]==1&&num==-1) orz[x]=0,cai[BIG-x]=0;
	js[x]+=num;
}
int query1(RI x) {return (orz&(orz<<x)).any();}
int query2(RI x) {return (orz&(cai>>(BIG-x))).any();}
int query3(RI x) {
	for(RI i=1;i*i<=x;++i) 
		if(x%i==0&&orz[i]&&orz[x/i]) return 1;
	return 0;
}
int main()
{
	n=read(),m=read(),sqn=sqrt(n);
	for(RI i=1;i<=n;++i) a[i]=read(),pos[i]=(i-1)/sqn+1;
	for(RI i=1;i<=m;++i) q[i]=(node){read(),read(),read(),read(),i};
	sort(q+1,q+1+m,cmp);
	RI he=1,ta=0;
	for(RI i=1;i<=m;++i) {
		while(ta<q[i].r) ++ta,add(a[ta],1);
		while(ta>q[i].r) add(a[ta],-1),--ta;
		while(he<q[i].l) add(a[he],-1),++he;
		while(he>q[i].l) --he,add(a[he],1);
		if(q[i].op==1) ans[q[i].id]=query1(q[i].x);
		else if(q[i].op==2) ans[q[i].id]=query2(q[i].x);
		else ans[q[i].id]=query3(q[i].x);
	}
	for(RI i=1;i<=m;++i) puts(ans[i]?"hana":"bi");
	return 0;
}
### 初始化与基本用法 C++ STL 中的 `bitset` 是一种用于处理固定大小位序列的容器,允许以二进制形式存储和操作数据。其初始化方式灵活,可以直接从整数或二进制字符串构造。 例如,以下代码将整数 20 转换为二进制,并存储到一个大小为 16 的 `bitset` 中: ```cpp #include <iostream> #include <bitset> int main() { std::bitset<16> bits(20); // 将整数20转换为16位的二进制表示 std::cout << bits << std::endl; // 输出: 0000000000010100 } ``` 也可以通过二进制字符串进行初始化: ```cpp std::bitset<8> bits_str("11001010"); std::cout << bits_str << std::endl; // 输出: 11001010 ``` 上述方法展示了如何在 C++ 中使用 `bitset` 进行初始化 [^2]。 ### 常见操作 `bitset` 提供了多种便捷的操作函数,包括设置、清除、翻转特定位置的位以及检查位的状态等。 - **设置位**:使用 `set(pos)` 方法可以将指定位置的位设为 1。 - **清除位**:使用 `reset(pos)` 方法可以将指定位置的位设为 0。 - **翻转位**:使用 `flip(pos)` 方法可以翻转指定位置的位值。 - **获取位状态**:使用 `test(pos)` 或 `[]` 操作符来获取指定位置的位值。 示例如下: ```cpp std::bitset<8> b; b.set(3); // 设置第3位为1 b.reset(2); // 清除第2位 b.flip(5); // 翻转第5位 bool isSet = b.test(3); // 检查第3位是否为1 ``` 这些操作使得 `bitset` 成为对位级操作非常高效的工具 [^2]。 ### 属性查询与转换 除了基本的位操作外,`bitset` 还提供了查询整体属性的方法,如: - **大小**:`size()` 返回 `bitset` 的总位数。 - **是否为空**:`none()` 检查是否所有位都为 0。 - **是否有任意一位为1**:`any()` 检查是否存在至少一个为 1 的位。 - **转换为整型**:`to_ulong()` 或 `to_ullong()` 可以将 `bitset` 转换为 `unsigned long` 或 `unsigned long long` 类型。 ```cpp std::bitset<8> b("10101010"); std::cout << "Size: " << b.size() << std::endl; // 输出: Size: 8 std::cout << "Any set bit? " << b.any() << std::endl; // 输出: Any set bit? 1 std::cout << "To unsigned long: " << b.to_ulong() << std::endl; // 输出: 170 ``` 这些功能扩展了 `bitset` 在数值计算和逻辑判断中的应用范围 [^2]。 ### 性能与适用场景 由于 `bitset` 使用紧凑的位存储结构,因此相比布尔数组等结构更加节省内存空间,适用于需要高效管理大量布尔标志的场合 [^1]。然而,需要注意的是 `bitset` 的大小是固定的,在编译时就已确定,无法动态调整。这种特性使其适用于静态配置信息或预定义状态的管理。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值