蓝桥赛前复习3:位运算

二进制中 1 的个数

题目描述

给定一个整数 xx,输出该数二进制表示中 1 的个数。

例:9 的二进制表示为 1001,有 2 位是 1 ,所以函数返回 2

输入描述

输入 xx​ (内存空间为 32 位的整数)。

输出描述

第一行输出 xx 二进制表示中 1 的个数。

输入输出样例

示例 1

输入

9

输出

2

先上代码

#include <iostream>
using namespace std;

int countOnes(int x) {
    //将 x 转为无符号,确保对负数也正确处理
    unsigned int u = static_cast<unsigned int>(x);
    int cnt = 0;
    //每次消去最低位的 1,直到 u 变为 0
    while (u) {
        u &= (u - 1);
        cnt++;
    }
    return cnt;
}

int main() {
    int x;
    if (!(cin >> x)) return 0;
    cout << countOnes(x) << "\n";
    return 0;
}

我们输入u=9;

第一次循环

第二次循环

位运算的操作

问题描述

对于一个整数,在计算机中是由二进制表示成的,从右往左依次从低位到高位,最右边是第 00 位。

例如 1313,其在计算机中的二进制为 11011101,原理为 1×20+0×21+1×22+1×23=131×20+0×21+1×22+1×23=13。

现在给定 11 个整数 nn 和 mm 次操作,操作具体为:

1 x:输出 nn 第 xx 位的值是 00 还是 11,例如 1313 的第 22 位值是 11。

2 l r:将 nn 第 ll 位到第 rr 位的值按位取反,然后输出 nn 的值。

3 l r:将 nn 第 ll 位到第 rr 位设置为 11,然后输出 nn 的值。

4 l r:将 nn 第 ll 位到第 rr 位设置为 00,然后输出 nn 的值。

5:输出该整数二进制中最后一个 11 所代表的值,例如 1101011010 你需要输出 22,1100011000 你需要输出 88,如果不存在 11 输出 00。

输入格式

第一行输入两个正整数 n,mn,m。 (1≤n<230,1≤m≤2×1051≤n<230,1≤m≤2×105)

接下来 mm 行,输入为其中 11 种:

1 x:输出 nn 第 xx 位的值,例如 1313 的第 22 位值是 11。(0≤x<30)(0≤x<30)

2 l r:将 nn 第 ll 位到第 rr 位的值按位取反,然后输出 nn 的值。(0≤l≤r≤30)(0≤l≤r≤30)

3 l r:将 nn 第 ll 位到第 rr 位设置为 11,然后输出 nn 的值。(0≤l≤r≤30)(0≤l≤r≤30)

4 l r:将 nn 第 ll 位到第 rr 位设置为 00,然后输出 nn 的值。(0≤l≤r≤30)(0≤l≤r≤30)

5:输出该整数二进制中最后一个 11 所代表的值,例如 1101011010 你需要输出 22,1100011000 你需要输出 88,如果不存在 11 输出 00。

输出格式

对于每次操作,按照题目要求输出。

样例输入

13 6
1 3
2 1 3
3 1 3
4 1 2
5
2 1 1

样例输出

1
3
15
9
1
11

说明

1313 的二进制为 11011101。

第一次操作输出 11。

第二次操作后二进制变成 00110011,输出 33。

第三次操作后二进制变成 11111111,输出 1515。

第四次操作后二进制操作变成 10011001,输出 99。

第五次操作输出 11。

第六次操作后二进制变成 10111011,输出 1111。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;  //读取 n 和 m
    
    while (m--) {
        int type;
        cin >> type;  //读取操作类型
        
        if (type == 1) {
            //操作 1 x: 查询第 x 位的值
            int x;
            cin >> x;
            cout << ((n >> x) & 1) << endl;
        }
        else if (type == 2) {
            //操作 2 l r: 按位取反
            int l, r;
            cin >> l >> r;
            int mask = 0;
            for (int i = l; i <= r; i++) {
                mask |= (1 << i);  //创建掩码
            }
            n ^= mask;  //对指定范围按位取反
            cout << n << endl;
        }
        else if (type == 3) {
            //操作 3 l r: 设置第 l 到 r 位为 1
            int l, r;
            cin >> l >> r;
            int mask = 0;
            for (int i = l; i <= r; i++) {
                mask |= (1 << i);  //创建掩码
            }
            n |= mask;  //对指定范围设置为 1
            cout << n << endl;
        }
        else if (type == 4) {
            //操作 4 l r: 设置第 l 到 r 位为 0
            int l, r;
            cin >> l >> r;
            int mask = 0;
            for (int i = l; i <= r; i++) {
                mask |= (1 << i);  //创建掩码
            }
            n &= ~mask;  //对指定范围设置为 0
            cout << n << endl;
        }
        else if (type == 5) {
            //操作 5: 输出最后一个 1 所表示的值
            cout << (n & (-n)) << endl;
        }
    }

    return 0;
}


详细说明
查询某一位的值 (操作 1):

输入的是位置 x,我们可以通过右移 n 为 n >> x,然后 & 1 得到该位置的二进制值。
cout << ((n >> x) & 1) << endl;


按位取反 (操作 2):

取反操作就是在一个给定的范围 [l, r] 内,翻转所有位。

我们首先生成一个掩码 mask,使得掩码中 [l, r] 位为 1,然后使用 n ^= mask 来进行按位取反操作。
int mask = 0;
for (int i = l; i <= r; i++) {
    mask |= (1 << i);
}
n ^= mask;


设置某一范围的位为 1 (操作 3):

我们同样生成掩码,使得 [l, r] 位为 1,然后通过 n |= mask 来将这些位设置为 1。
int mask = 0;
for (int i = l; i <= r; i++) {
    mask |= (1 << i);
}
n |= mask;


设置某一范围的位为 0 (操作 4):

这里,我们生成掩码后,通过 n &= ~mask 来将指定范围内的位清零。
int mask = 0;
for (int i = l; i <= r; i++) {
    mask |= (1 << i);
}
n &= ~mask;


输出最后一个 1 所表示的值 (操作 5):

这个操作可以通过 n & (-n) 得到。这个公式是利用了补码的特性,它能提取出二进制数中最后一个 1 所表示的值。
cout << (n & (-n)) << endl;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值