【基本算法】位运算基础
知识点
特殊的十六进制
0x7F FF FF FF = INT_MAX
;(32位)0x3F FF FF FF
满足:- 两倍不超过
int
; - 每8个字节相同;
- 两倍不超过
0xFF FF FF FF = -1
;
数组初始化
memset(a, 0x3f, sizeof(a)); //只能赋值每8位都相同的int
左移和右移
1
<
<
n
=
2
n
;
1 << n = 2^n;
1<<n=2n;
n
<
<
1
=
2
∗
n
;
n << 1 = 2*n;
n<<1=2∗n;
算术右移(编译器通常实现都是算术右移)
n > > 1 = ( n / 2.0 ) 向 零 取 整 n >> 1 = (n / 2.0)向零取整 n>>1=(n/2.0)向零取整
二进制状态压缩
(n >> k) & 1
取出整数n
在二进制表示下的第k
位;n & ((k << 1) - 1)
取出整数n
在二进制表示下的第0
到k-1
位;n ^ (1 << k)
把整数n
在二进制表示下的第k
位取反;n | (1 << k)
将整数n
在二进制表示下的第k
位赋值1;n & (~(1 << k))
将整数n
在二进制表示下的第k
位赋值0;
成对计算
对于非负整数n
:
n
为偶数:x ^ 1 == n + 1
;n
为奇数:x ^ 1 == n - 1
;
(0, 1)、(2, 3)、(4, 5)、(6, 7)、(8, 9)
对1
异或运算构成成对变换;
LowBit
lowbit(n) = n & (~n + 1) = n & (-n)
该运算符的运算结果为n
在二进制表示下最低位的1
及后面所有的0
,其为树状数组(BIT) 中的一个基本运算。
应用: 找出整数二进制表示下是1的所有位:
vector<int> FindOnePosition(int n){
unordered_map<int,int> h;
// 预计算
for(int i = 0; i <= 20; ++i) h[1 << i] = i;
vector<int> ans;
while(n){
ans.push_back(h[n & -n]);
n -= (n & -n);
}
}
例题
89. a ^ b (快速幂):
挑战成功时间1分30秒;
// 理解思路:将b按位分解;
long long quickPow(long long a, long long b, long long p){
long long ans = 1 % p;
while(b){
if(b & 1) ans = ans * a % p; //乘法与取余优先级相同
a = a * a % p;
b >>= 1;
}
return ans;
}
90. 64位整数乘法:
题目链接
挑战成功时间1分11秒;
long long mul(long long a, long long b, long long p){
long long ans = 0;
while(b){
if(b & 1) ans = (ans + a) % p;
a = a * 2 % p;
b >>= 1;
}
return ans;
}
91. 最短Hamilton路径:
题目链接
挑战成功时间4分8秒;
int hamilton(int n, vector<vector<int>>& G){
vector<vector<int>> dp(1 << n, vector<int>(n, INT_MAX / 2));
dp[1][0] = 0;
for(int i = 2; i < 1 << n; ++i){
for(int j = 1; j < n; ++j) if((1 << j) & i){
for(int k = 0; k < n; ++k) if((i ^ (1 << j)) & (1 << k)){
dp[i][j] = min(dp[i][j], dp[i ^ (1 << j)][k] + G[j][k]);
}
}
}
return dp[(1 << n) - 1][n-1];
}
998. 起床困难综合症:
题目链接
挑战成功时间3分55秒
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
int m, n;
cin >> n >> m;
vector<string> op(n);
vector<int> v(n);
for(int i = 0; i < n; ++i){
cin >> op[i] >> v[i];
}
int k = 30;
int ans = 0;
int st = 0;
while(k >= 0){
int a = 1;
int b = 0;
for(int i = 0; i < n; ++i){
int bit = (v[i] >> k) & 1;
if(op[i][0] == 'A'){
a &= bit;
b &= bit;
}else if(op[i][0] == 'O'){
a |= bit;
b |= bit;
}else{
a ^= bit;
b ^= bit;
}
}
if(b == 1) ans |= (1 << k);
else if(a == 1 && (st | (1 << k)) <= m){
ans |= (1 << k);
st |= (1 << k);
}
k--;
}
cout << ans << endl;
return 0;
}