一个x ,当x不为零时进行如下操作
- 如果二进制x中有奇数个1,则x二进制形式下最低位取反
- 如果二进制xxx中有偶数个1,则x二进制形式下非前导零最高位取反
询问对于一个x,操作几次后变为零
🔍 问题本质与规律分析
通过枚举小数字的二进制表示和操作序列,可以发现操作次数与二进制数的两个特征密切相关:
- 最低位(LSB)的值(记为
L,0 或 1) - 除最低位外,其他高位中 1 的个数(记为
S)
具体的计算规律如下:
-
如果 最低位
L = 1(即x为奇数):- 若
S为奇数,则操作次数 = 2 × S - 若
S为偶数,则操作次数 = 2 × S + 1
- 若
-
如果 最低位
L = 0(即x为偶数):- 若
S为奇数,则操作次数 = 2 × S + 1 - 若
S为偶数,则操作次数 = 2 × S
- 若
📝 计算步骤与示例
您可以按照以下步骤计算任意非零整数 x的操作次数:
- 将
x转换为二进制字符串(忽略前导零)。 - 确定最低位
L:即二进制串最右边的数字。 - 计算
S:即二进制串中除了最低位以外所有位值为1的个数。 - 根据上述规律公式计算操作次数。
示例验证:
-
x = 2(二进制10):L = 0,S = 1(只有高位的一个1)L=0且S为奇数 → 操作次数 = 2×1 + 1 = 3- 操作序列:
10(2) →11(3) →01(1) →00(0) ✅
-
x = 3(二进制11):L = 1,S = 1L=1且S为奇数 → 操作次数 = 2×1 = 2- 操作序列:
11(3) →01(1) →00(0) ✅
-
x = 1(二进制1):L = 1,S = 0(无其他位)L=1且S为偶数 → 操作次数 = 2×0 + 1 = 1 ✅
💡 实现建议
在编程实现时,您可以直接通过位运算提取 L和计算 S,无需转换二进制字符串:
L = x & 1(取最低位)S = (x >> 1)的二进制中1的个数(即x右移一位后的 popcount)- 计算 popcount 可使用高效位操作(如
n & (n-1)消除最低位 1 的技巧)。
💎 代码实现
该问题的关键规律在于二进制表示中最低位和高位 1 的个数的奇偶性组合直接决定了操作次数。通过上述公式,您可以在 O(1) 的时间复杂度内计算出结果,避免了逐步模拟的耗时操作。
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
// Write your code here
let params = [];
while ((line = await readline())) {
let tokens = line.split(" ");
// let a = parseInt(tokens[0]);
// let b = parseInt(tokens[1]);
// console.log(a + b);
params.push(tokens);
}
// console.log(params)
let T = parseInt(params[0][0]);
for (let i = 1; i <= T; i++) {
let num = parseInt(params[i][0]);
// console.log(num)
let L = num & 1; // 最后一位
let S = 0;
let tmp = num;
while (tmp != 0) {
tmp = tmp & (tmp - 1);
S++;
}
S = S - L; // 除低位之外的1的数量
// 根据奇偶性输出结果
if (L === 1) {
console.log(S % 2 === 0 ? 2 * S + 1 : 2 * S);
} else {
console.log(S % 2 === 0 ? 2 * S : 2 * S + 1);
}
}
})();