首页 > 试题广场 >

小红的二进制操作

[编程题]小红的二进制操作
  • 热度指数:349 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红拿到了一个数组,她可以进行最多两次操作:选择一个元素,使其加1。
小红希望操作结束后,数组所有元素乘积的二进制末尾有尽可能多的0。你能帮帮她吗?

输入描述:
第一行输入一个正整数 n,代表数组的大小。
第二行输入 n 个正整数 a_i,代表数组的元素。
1 \leq n \leq 10^5
1 \leq a_i \leq 10^9


输出描述:
输出一个整数,代表操作结束后,数组所有元素乘积的二进制末尾0的数量。
示例1

输入

5
1 2 3 4 5

输出

6

说明

操作两次后数组变为 [2, 2, 4, 4, 5],数组乘积为 320,二进制表示为 101000000,有 6 个 0。

想要乘积的末尾的0最多,那就要数组中的数的2的因子要多,所以可以先求出原数组中的总共的2的因子的个数
然后去枚举每个元素,对同一个元素进行2次+1,然后求差值,
然后再去求出对原数组的2个元素,对这2个元素各加1带来的2的因子的增加,
然后求这2种情况的最大值



const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void async function () {
    let n = parseInt(await readline());
    let arr = (await readline()).split(' ').map(Number);
    
    // 使用位运算计算每个数中因子2的个数
    function countFactorsOf2(num) {
        if (num === 0) return 0;
        let count = 0;
        while ((num & 1) === 0) {
            count++;
            num >>= 1;
        }
        return count;
    }
    
    // 计算原始数组中因子2的总个数
    let totalFactors = 0;
    let gains = [];
    
    for (let i = 0; i < n; i++) {
        let original = countFactorsOf2(arr[i]);
        let afterPlusOne = countFactorsOf2(arr[i] + 1);
        totalFactors += original;
        gains.push(afterPlusOne - original);
    }
    
    // 对增益进行排序
    gains.sort((a, b) => b - a);
    
    // 最多两次操作的最大增益
    let maxGain = 0;
    
    // 情况1: 两次操作作用于同一元素 (+2)
    for (let i = 0; i < n; i++) {
        let gainFromTwoOps = countFactorsOf2(arr[i] + 2) - countFactorsOf2(arr[i]);
        maxGain = Math.max(maxGain, gainFromTwoOps);
    }
    
    // 情况2: 两次操作作用于不同元素 (各+1)
    let gainFromTwoElements = Math.max(0, gains[0] || 0) + Math.max(0, gains[1] || 0);
    maxGain = Math.max(maxGain, gainFromTwoElements);
    
    console.log(totalFactors + maxGain);
}()

发表于 2025-08-02 14:49:50 回复(0)