实用技巧
位运算
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
这篇写完,我自己都提升了,难道不值得赞吗???