实用技巧之位运算

实用技巧

位运算
1(十进制)=01(二进制)

&

两个二进制码位置如果同时是1则结果为1,其余为0
b&1
所以“&1”“%2”是判断奇偶的,是奇数则为1

>>

右移运算
1.二进制码向右挪x个长度,右边挤掉
2.可以取出二进制表示下的某一位,例如:n^(1<<k)表示二进制下第k位去取反。
b>>=1
“>>1”=除二
b>>x就可以取出b的二进制码中的第x位
(x是一个数字)

b&1可以取出b在二进制表示下的最低位
b>>1可以舍去最低位

<<

左移运算
1<<b求2的b次方
常用long long len = 1 ll<<(n-1);
long long cnt = 1 ll<< (2*n-2);
注意类型转换
1<<n
左移运算在图中的应用就是标记遍历的点,1表示这个位置没有被走过,0表示已经走过,每运算一次,就左移一下

^

异或运算
两个相同则为0,否则为一

1.两个相同数异或的结果为0
2.0异或任何数都为那个数

应用:
在一组数中找出不同的数

例1:一个数组中,只有一个数出现了一次,请你找出这个数,其余的都是2次
前缀和+异或
全部数异或后结果就是那个单次的数(有重复的都异或为0了)

int n;
cin>>n;
int a[n+1];
a[0]=0;
for(int i=1;i<=n;i++){
    cin>>a[i];
    a[i]^=a[i-1];
}
cout<<a[n];

例2:
一个数组中有2个出现一次的数,请你求出这2数
分析
要想找出两个单次的数,其实我们只需要将这个数组一分为二,保证这两部分各包含一个出现一次的数
目标转换:
求如何分解数组
根据上题经验,全部异或的结果肯定是那两个单次数异或的结果
所以异或的结果中的二进制码中肯定有1
而那个1就是这两个单次出现的数的不同之处
于是我们记录这个位置pos
所以我们可以依据数组中的数的pos位置有无1来将数组分为两大类
分完类,做法就与例1做法一样了

提示:
我们可以使用“>>”来取出每个位置,并用&运算来判断这个位置是否是1

int n;
cin>>n;
int a[n+1];
a[0]=0;
int num=0;
int a1=0,a2=0;
for(int i=1;i<=n;i++){
    cin>>a[i];
    num^=a[i];
}
int pos= 0 ;
for(int i=0;i<32;i++){
    if(((num>>i)&1) == 1){
        pos=i;
        break;
    }
}
for(int i=1;i<=n;i++){
    if(((a[i]>>pos)&1)==1){
        a1^=a[i];
    }else{
        a2^=a[i];
    }
}
cout<<a1<<" "<<a2;

|

或运算
例1给你一个数组,求将这个数组的每个数组合搭配后形成小数组,小数组的值按位或后,有多少种不同的结果
样例:1 1 1 2

这篇写完,我自己都提升了,难道不值得赞吗???

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章