【基本算法】位运算

知识点

特殊的十六进制

  • 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=2n;
算术右移(编译器通常实现都是算术右移)

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在二进制表示下的第0k-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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值