二进制中 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;