基本运算方式
与
二进制下:
0 & 0 = 0 0 & 1 = 0
1 & 0 = 0 1 & 1 = 1
或
二进制下:
0 | 0 = 0 0 | 1 = 1
1 | 0 = 0 1 | 1 = 1
非
!0 = 1(true) !x = 0(false)
x为所有非零数。
异或
二进制下:
0 ^ 0 = 0 1 ^ 1 = 0
1 ^ 0 = 1 0 ^ 1 = 1
取反
二进制下:
~01001 = 10110
移位
二进制下:
原数:1000011
左移一位:<< 1 变为:0000110(高位溢出)
右移一位:>> 1 变为:0100001(低位溢出)
基本性质
1. 异或
交换律
a ^ b = b ^ a
结合律
a ^ (b ^ c) = (a ^ b) ^ c
无分配律
2. a + b >= a ^ b
证明:a + b = 2(a & b) + a ^ b
运用方式(例题)
二进制中1的个数
题目描述
给定一个长度为n的整数数组a,你需要求出每个元素的二进制表示中1的个数。
输入
第一行:一个整数n;
第二行:n个整数,表示数组a。
输出
共一行,输出n个整数,其中第i个数为a[i]的二进制中1的个数。
题目分析 / 实现思路
本题我们可以用&将a[i]与1进行比较。如果二进制下的a[i]最后一位为1,那么a[i] & 1的值为true,反之便为false。在进行了该运算后我们便可将 a[i]右移一位,进行下一轮的运算,直到a[i]的值为零。这样我们便可求出a[i]二进制下1的个数。
代码实现
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 加速cin / cout
int n;cin >> n;
for (int i = 0;i < n;i++)
{
int x, res = 0;cin >> x;
while (x) if (x & 1) res++, x >>= 1; else x >>= 1;
cout << res << ' ';
}
return 0;
}
注:使用Day3中讲到的bitset可以直接做。
我们需要0
题目描述
给定一个大小为n的非负整数数组a。
你可以选定一个非负整数x,并令b[i] = a[i] ^ x,请问是否存在x,使得b[1] ^ b[2] ^ … ^ b[n] = 0?
输入
第一行:一个整数t,代表有t个案例,对于每个案例:
第一行:一个整数n(奇数),表示数组大小;
第二行:n个整数,表示数组a。
输出
对于每个案例:若存在符合条件的x,则输出x;否则输出-1。
题目分析 / 实现思路
原式为:
(a1 ^ x) ^ (a2 ^ x) ^ ... ^ (an ^ x) = 0
利用结合律可将括号拆开,并使用交换律,得原式等价于:
a1 ^ a2 ^ ... ^ an ^ x ^ .. ^ x = 0
化简得:
a1 ^ a2 ^ ... ^ an ^ x = 0
要求得x,我们只需实现其逆运算即可。
即:
x = a1 ^ a2 ^ ... ^ an
代码实现
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;cin >> t;
while (t--)
{
int n;cin >> n;
long long res = 0;
for (int i = 0;i < n;i++)
{
int a;cin >> a;
res ^= a;
}
cout << res << '\n';
}
return 0;
}