a>>j&1 把a转化成二进制之后第j个位置的值
>>运算是整体右移动
&1运算取出二进制的最后一位
所以a>>j&1 如果我们要取数,要用&1取,但是&1是取最后一位,我们需要移动a,把想要去的第j位移动到最后一位。也就是右移j位。
通着这个操作统计每一个数字的每一个位置的总值。
最后都%3,因为如果a数字出现三次,每个位置都对应出现了三次,%3后是归零的。只会剩下那个单独一个的
最后我们要把sum变成十进制。
我们知道对于010101
十进制 = 0*2^0 + 1*2^1 + 0*2^2 + 1*2^3 + 0*2^4 + 1*2^5
=sum[i]*2^i + ....
<<运算,就是当前树乘以2的几次房。
所以就是sum[i]<<i;
//补充知识
&运算
0 & 0=0
0 & 1=0
1 & 0=0
1 & 1=1
可用来用于判断奇偶和取最后一位数
因为&1,如果最后一位是0,则为0.如果最后一位是1,则为1
一般就是&1,不会&其他的
|运算
0 & 0=0
0 & 1=1
1 & 0=0
1 & 1=1
直接|1,可以让最后一位强行变成1
这一个操作可以让当前数字变成最接近他的偶数
^ 运算
0 & 0=0
0 & 1=1
1 & 0=1
1 & 1=0
就是让一个数完全变成相反的
可以不利用其他变量进行交换a^=b^=a^=b;(可以不借助别的变量)
检查两个数是否相等a^b=0,则相等
一个数如果同时^两次,那么不变
例题:
如果m个数,其中只有一个数出现了奇数次,就那么数
不停的异或即可,最终值就是那个奇数
<< 运算左移运算,乘以2的几次方
常用于把二进制转化成十进制
十进制 = 0*2^0 + 1*2^1 + 0*2^2 + 1*2^3 + 0*2^4 + 1*2^5
=sum[i]*2^i + ....
<<运算,就是当前树乘以2的几次房。
所以就是sum[i]<<i;
>> 运算
右移运算符。
有些操作我们只能对最后一位处理,我们需要这样移动过去进行处理
对于某些问题,比如什么一个数出现了几次啦,关于数字的操作问题的题目,可以思考一下是否能用到位运算
#include<algorithm>
#include<string.h>
using namespace std;
int sum[32],n,a;
int main()
{
memset(sum,0,sizeof(sum));
cin>>n;
for(int i=0; i<n; i++)
{
cin>>a;
for(int j=0; j<32; j++)
{
sum[j]+=a>>j&1; //a>>j&1 的意思是a转化为二进制后第j个位置的值
sum[j]%=3; //我们统计所有数字j位置的综合。 之后%3,因为出现三次,%3就归零了
} //只会剩下那个出现一次的,要不是1,要不是0.而j从0-32表示的就是最后那个单独的数
}
int ans = 0;
for(int i=0; i<32; i++)
{
ans += sum[i]<<i; //把二进制数转化成十进制
}
cout<<ans<<endl;
}