位运算
本文代码适用于c++
什么是位运算
计算机中整数以二进制的形式存储在内存中。位运算即直接对整数的二进制进行二进制特有的运算。
一些约定
对于n位二进制整数,最右边为第0位(最低位),最左边为n-1位(最高位)。
默认对进行位运算的两个二进制整数位数相同(对位数较小的补0)。
暂时不考虑负数的位运算。
常见位运算
记xi为x的第i位数码,yi为y的第i位数码,zi同理
1.按位与
z=x&y ;则zi=1 当且仅当 xi=yi=1;
2.按位或
z=x|y ;则zi=1 当且仅当 xi,yi中至少有一个为1
3.按位异或
z=x^y ;则zi=1 当且仅当xi,yi中恰有一个为1
4.按位取反
z=~x ; 则zi=1 当且仅当 xi=1
5.左移/右移
x<<i/x>>i :把x向左/右整体移动i位(低位去0高位补0)
(111>>2)=1;(111<<2)=11100;
左移右移可以用来进行2的幂次的计算,如
x<<i :x*2^i
x>>i : [x/(2^i)]
(当i>30时 1<<i要改写成1ull<<i)
位运算在集合运算
集合的表示
给定两个集合 X,Y; |X并Y|=32,a0 a1--a31;
我们考虑用二进制数表示X集合:
xi=1当且仅当ai在X中
集合的运算
不难看出,利用位运算我们可以得到:
X并Y=x|y;
x交Y=x&y;
x在y中的补集=(x&y)^y
STL位运算--bitset
在用二进制表示集合时候,我们发现即使是unsigned long long最多也不过128个元素。遇到集合更大的情况怎么办呢?
std::bitset<N>s;//声明位数为N的二进制串s
s.set(i, 0); //将s的第i位数码改为0
s.set(i, 1); //将s的第i位数码改为1
s.test(i);//返回si的数值
s.count();//返回s中1的数目
s.reset();//将s设为全0`
<< ,>>, &, |, ~,也可以对bitset运算
例题(luogu)
1.B3695https://www.luogu.com.cn/problem/B3695
using namespace std;
std::bitset<30005> ss[30005];
std::bitset<30005> temp;
int main()
{
int n,m,q,tmp;
int c[1000006];
int x,y,o;
cin>>n>>m>>q;
for(int i=0;i<m;i++)
temp.set(i,1);
for(int i=1;i<=n;i++)
{
cin>>c[i];
for(int j=0;j<c[i];j++)
{
cin>>tmp;
ss[i].set(tmp-1,1);//若j在集合si中 si的第j-1位为1
}
}
while(q--)
{
scanf("%d %d %d",&o,&x,&y);
if(o==1)
{
ss[x]=((ss[x]<<y)&temp);
}
else if(o==2)
{
ss[x]=(ss[x]>>y);
}
else if(o==3)
cout<<(ss[x]&ss[y]).count()<<endl;//交
else if(o==4)
cout<<(ss[x]|ss[y]).count()<<endl;//并
else if(o==5)
cout<<(((ss[x]&ss[y])^ss[x])|((ss[x]&ss[y])^ss[y])).count()<<endl;//ssx与ssy的对称差
}
return 0;
}

浙公网安备 33010602011771号