数字游戏

42 阅读3分钟

一个x ,当x不为零时进行如下操作

  • 如果二进制x中有奇数个1,则x二进制形式下最低位取反
  • 如果二进制xxx中有偶数个1,则x二进制形式下非前导零最高位取反

询问对于一个x,操作几次后变为零

ac.nowcoder.com/acm/contest…

🔍 问题本质与规律分析

通过枚举小数字的二进制表示和操作序列,可以发现操作次数与二进制数的两个特征密切相关:

  • ​最低位(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的操作次数:

  1. x转换为二进制字符串(忽略前导零)。
  2. 确定最低位 L:即二进制串最右边的数字。
  3. 计算 S:即二进制串中​​除了最低位​​以外所有位值为 1的个数。
  4. 根据上述规律公式计算操作次数。

​示例验证​​:

  • x = 2(二进制 10)​​:

    • L = 0S = 1(只有高位的一个 1
    • L=0S为奇数 → 操作次数 = 2×1 + 1 = ​​3​
    • 操作序列:10(2) → 11(3) → 01(1) → 00(0) ✅
  • x = 3(二进制 11)​​:

    • L = 1S = 1
    • L=1S为奇数 → 操作次数 = 2×1 = ​​2​
    • 操作序列:11(3) → 01(1) → 00(0) ✅
  • x = 1(二进制 1)​​:

    • L = 1S = 0(无其他位)
    • L=1S为偶数 → 操作次数 = 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);
        }
    }
})();