这里写目录标题
C++标准库bitset对象的初始化及操作
// bit当作数组,下标0对应的是最右边的元素
bitset<10> bit;
bit[0]=1;//0000000001
cout<<bit<<endl;
bit[9]=1;//1000000001,上次的bit[0]=1噢
cout<<bit<<endl;
bitset<10> b(string("11101"));
cout<<b<<endl;
bitset<10> b1(5);
cout<<b1<<endl;
// bitset常见的两种初始化方式是通过string和整数(二进制形式)
//进行初始化,要以构造函数的形式噢,bit (string("110101011"))是错的
bitset<容量>bit (string("110101011")) ;//110101011
bitset<容量>bit(5);//101
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
bitset<16> bitvec; //初始化16位,全0
bool is_set = bitvec.any(); //存在置为1的二进制位吗?否,返回false
bool is_not_set = bitvec.none(); //不存在1的二进制位吗?是,返回true
size_t bits_set = bitvec.count();//置为1的二进制位的个数,0
size_t sz = bitvec.size(); //二进制位的个数,16
cout<<"bitvec:"<<endl<<bitvec<<endl;
//下标操作符
for (int index=0;index!=bitvec.size();index+=2)
{
bitvec[index] = 1;
}
cout<<"下标操作符,置偶数位为1:"<<endl<<bitvec<<endl;
//reset操作
bitvec.reset();
cout<<"reset操作,所有二进制位都置为0:"<<endl<<bitvec<<endl;
//set操作
for (int index=0;index!=bitvec.size();index+=2)
{
bitvec.set(index);
}
cout<<"set操作,置偶数位为1:"<<endl<<bitvec<<endl;
//set操作
bitvec.set();
cout<<"set操作,所有二进制位都置为1:"<<endl<<bitvec<<endl;
//flip操作
bitvec.flip();
cout<<"flip操作,所有二进制位逐位取反:"<<endl<<bitvec<<endl;
//flip操作
for (int index=0;index!=bitvec.size();index+=2)
{
bitvec.flip(index);
}
cout<<"flip操作,将偶数位取反:"<<endl<<bitvec<<endl;
//获取bitset对象的值
unsigned long ulong = bitvec.to_ulong();
cout<<"bitvec返回unsigend long值为:"<<ulong<<endl;
return 0;
}
bitset上场
BZOJ3687: 简单题(dp+bitset)
Description
小呆开始研究集合论了,他提出了关于一个数集四个问题:
1.子集的异或和的算术和。
2.子集的异或和的异或和。
3.子集的算术和的算术和。
4.子集的算术和的异或和。
目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把
这个问题交给你,未来的集训队队员来实现。
Input
第一行,一个整数n。
第二行,n个正整数,表示01,a2….,。
Output
一行,包含一个整数,表示所有子集和的异或和。
Sample Input
2
1 3
Sample Output
6
HINT
【样例解释】
6=1 (异或) 3 (异或) (1+3)
【数据规模与约定】
ai >0,1<n<1000,∑ai≤2000000。
另外,不保证集合中的数满足互异性,即有可能出现Ai= Aj且i不等于J
题意:给出一个序列,要求出所有子集异或的结果。
如何优化枚举子集?So hard。
416. Partition Equal Subset Sum(解释恰好装满型)这题要求将一个序列划分为两个元素之和相等的子集,一种做法是当作背包问题,选若干物品装满容量为sum/2的背包。
另一种 利用bool数组—>bitset,
bitset相当于bool数组,bool[sum]=1表示能得到各商品总和为sum的组合
用bitset来记录这些商品所有可能组合的和。
具体步骤是: 开辟一个大小为5001的bisets(因为所有元素和不超过10000)名为bits,最后得到的bits满足bits[i]=1则代表nums中某些元素的和为i,最后判断bits[sum/2]是否为1即可
初始时bits[0] = 1,然后从前往后遍历nums数组,对于当前遍历到的数字num,把 bits 向左平移 num 位,然后再或上原来的 bits,这样就代表在原先的基础上又新增了一个和的可能性。 比如对于数组 [1,3],初始化 bits 为 …00001,遍历到1,bits 变为…00011,然后遍历到3,bits 变为了 …11011。最终得到的bit在第1,3,4位上为1,代表了可能的和为1,3,4,这样遍历完整个数组后,去看 bits[sum/2] 是否为1即可。
00000000000001//初始bit[0]=1
00000000000010//左移1位
--->00000000000011//包含了组合为0,1的可能
00000000001100//左移2位
--->00000000001111//包含了组合为0,1,2,3的可能
00000001111000//左移3位
--->00000001111111//包含了组合为0,1,2,3,4,5,6的可能
00111111100000//左移5位
--->00111111111111//包含了0,1,2,3,4,5,6,7,8,9,10,11这所有的可能
其实也很好理解呀,bit=bit|(bit<<nums[i]);
前一个bit保留了上一次得到的所有组合结果,后一个bit<<nums[i]
,在上一次得到的每个结果的基础上加上nums[i]
取nums[i]
的所有情况都包含在后者里,不取nums[i]
的所有情况都包含在前者中
这实际上是个非常暴力的思想,但是借助位运算和bit非常巧妙的极大优化
bool canPartition(vector<int>& nums) {
int n=nums.size();
int sum=0;
for(int i=0;i<n;i++){
sum+=nums[i];
}
if(sum&1)return false;//sum奇数
sum >>= 1;
bitset<10005> bit(1);//所有元素之和不会超过20000,一半就是10000
// 相当于bit[0]=1啦
for(int i=0;i<n;i++){
bit=bit|(bit<<nums[i]);
}
if(bit[sum])return true;
else return false;
}
所以这题就用bitset, 依旧是记录,随着一个个元素的加入,将所有产生的子集
思路:用bitset记录某个数是否在子集和中出现,利用bitset对二进制位的快速大量操作(移位),通过已经求出的子集和求出剩余的子集和
#include<iostream>
#include <bitset>
using namespace std;
const int N=1005;
int a[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
bitset<2000005> bit;
bit[0]=1;//和为0的子集显然是有的
int sum=0;
for(int i=1;i<=n;i++){//和0异或为本身,和1异或相反,相同为0
bit^=(bit<<a[i]);
sum+=a[i];
}
int res=0;
for(int i=0;i<=sum;i++){
if(bit[i])res^=i;
}
cout<<res;
return 0;
}
为什么不bit | = ( bit < < a[i] )
呢?
bit|=(bit<<a[i]);
记录所有不同值的子集,但无法确定某个值的子集
有多少种组合而来的方式,而这题要求,不同组合产生的相同值的子集也要进行 异或
产生两个(偶数个)相同子集之后,异或肯定得0(根据异或的性质可知,偶数个相同的数是没有影响的)
将两个bitset对应的状态按位异或,消去的就是两个相同值的子集
相当于看作不能产生这个值的子集了,因为对最后异或的结果贡献为0
集合中删去指定的3个数,再在集合种取10个数是否构成87
【01背包 && bitset优化 && 取 10 个数构成 78 的方案数】HDU - 5890 Eighty seven
bitset优化,枚举 所有可能 10个数组合 出现的子集情况
和枚举所有元素的子集不同,首先得通过二重循环选出10个数(删去的不能选),再逐一加入选出的10个数,构成bitset状态
选出10个数,10代表容量啦,恰好装满型,dp值只有0和1