bitset用法及例题
参考:
https://blog.csdn.net/snowy_smile/article/details/79120063
1.bitset有什么用?
优化代码运行的时间和空间
具体地,空间为 S/8 , 时间为 T/w (w通常为32,与计算机的机器字长有关)
2.bitset是什么
可以理解成N位(自己可设置)二进制位
和bool数组的区别:bool类型变量占用1字节内存,而每个bitset占用1bit内存
测试代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
bool a[32];
cout<<sizeof(a)<<endl;
bitset<32>b;
cout<<sizeof(b)<<endl;
system("pause");
return 0;
}
3.bitset相关函数
其常用函数如下:
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.set(pos)
把b[pos]置为1
b.reset()
把b中所有二进制位都置为0
b.reset(pos) 把b[pos]置为0
b.flip()
把b中所有二进制位逐位取反
b.flip(pos)
把b[pos]取反
4.例题
例题1. 共有n个数,每个数的取值范围是[],S=,求S的不同种类数
https://ac.nowcoder.com/acm/problem/17193
很容易想到dp方程:
//首先容易发现S的取值范围为1e6,用dp[i]表示i能否被取到
for i in [1,n]
for k in [li,ri]
for j in [1,1e6]
dp[j]=dp[j]|dp[j-k*k]
然而时间复杂度太大
正解:
用大小为1e6的bitset表示每一个数能否取到(例如,第3位为1表示能取到3,第1位为0表示不能取到1)
dp[0][0]=1;
for(int i=1;i<=n;i++){
cin>>l[i]>>r[i];
for(int j=l[i];j<=r[i];j++){
dp[i]|=(dp[i-1]<<(j*j)); //dp[i]表示前i个数的平方和的取值情况,每一位取值1表示能,0表示不能。如果某一位在dp[i]已经能取到1,或者前i-1个数不能,但是加上j*j就可以,那么这一位的值为1
}
}
printf("%d\n",dp[n].count());
例题2.给你n个数,每次可以从中拿走1-3个数,问你有没有可能在留下的数中选取恰好10个数,使得他们的和为87
https://acm.hdu.edu.cn/showproblem.php?pid=5890
本题的做法是开87位的bitset,存储每个数(1~87)是否能被取到。
细节见代码
另外还需要优化时间复杂度,开一个数组记录每次拿走的数即可
int a[55];
bool vis[55];
bitset<100>dp[11];
int ans[55][55][55];
bool solve(){ //任意选10个数能否凑出87
for(int i=0;i<=10;i++) dp[i].reset();
dp[0][0]=1;
for(int i=1;i<=n;i++){
if(!vis[i]||a[i]>87) continue;
for(int j=10;j>=1;j--){
dp[j]|=(dp[j-1]<<a[i]);
}
}
if(dp[10][87]) return 1;
else return 0;
}
int main(){
scanf("%d",&t);
while(t--){
memset(ans,-1,sizeof(ans));
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),vis[i]=1;
scanf("%d",&m);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if(x>y) swap(x,y);
if(y>z) swap(y,z);
if(x>y) swap(x,y);
vis[x]=vis[y]=vis[z]=0;
if(ans[x][y][z]==-1) ans[x][y][z]=solve();
if(ans[x][y][z]) puts("Yes");
else puts("No");
vis[x]=vis[y]=vis[z]=1;
}
}
system("pause");
return 0;
}
例题3.bitset优化背包问题:给你n件物品,有各自的重量和价值。问你在总重量一定的情况下,所有物品价值的异或和最大能是多少。
本题没有提交链接
分析:
首先明确一个事实,价值的异或和是必须记录在状态中的,因为不一定从上一个最优状态能转移到下一个最优状态。(例如父状态选取物品1最优,子状态选取物品2+4最优。)
暴力做法: dp[W][V]=max(__,dp[W-w[i][V^v[i]]); 时间复杂度O(nWV) tle!
优化:开V个大小为W的bitset,存储异或和为V时的重量,这样做。
#include<bits/stdc++.h>
using namespace std;
const int N = 1024;
int t,n,m;
int w[N],v[N];
bitset<N>dp[N],tem[N];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d",&w[i],&v[i]);
}
for(int i=0;i<1024;i++) dp[i].reset();
dp[0][0]=1;
for(int i=1;i<=n;i++){
// for(int j=;;j){ ///?
// dp[j^v[i]]|=(dp[j]<<w[i]); //dp[j]不一定是做过的
// }
for(int j=0;j<1024;j++){
tem[j^v[i]]=(dp[j]<<w[i]);
}
for(int j=0;j<1024;j++){
dp[j]|=(tem[j]);
}
for(int j=0;j<1024;j++){
tem[j]=0;
}
}
int ans=-1;
for(int i=1023;i>=0;i--){
if(dp[i][m]){
ans=i;
break;
}
}
printf("%d\n",ans);
}
system("pause");
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效