bitset优化(bitset枚举一个序列所有子集)

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

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值