异或和之和

17 阅读2分钟

问题描述

  • •​​输入​​:一个数组包含 n个正整数。

  • •​​要求​​:从数组中任取三个不同的数,计算每个三元组的异或值(即 a⊕b⊕c),并将所有三元组的异或值求和。

  • •​​输出​​:求和结果对 109+7取模的值

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 n = BigInt(params[0][0]);
    let arr = params[1].map((v) => BigInt(v));
    const MOD = 1000000007n; // 使用BigInt表示模数

    /**
     * 快速幂函数,计算 base^exp % mod
     * 使用BigInt处理大数运算
     */
    function quickPow(base, exp, mod) {
        let res = 1n;
        base = base % mod;
        while (exp > 0) {
            if (exp & 1n) {
                res = (res * base) % mod;
            }
            base = (base * base) % mod;
            exp = exp >> 1n;
        }
        return res;
    }

    /**
     * 计算组合数 C(a, b) % MOD
     * 使用BigInt参数,处理大整数组合数
     */
    function nCr(n, r) {
        if (r < 0n || r > n) return 0n;
        if (r === 0n || r === n) return 1n;
        if (r > n - r) r = n - r; // 利用组合数性质优化

        let numerator = 1n;
        let denominator = 1n;

        for (let i = 0n; i < r; i++) {
            numerator = (numerator * (n - i)) % MOD;
            denominator = (denominator * (i + 1n)) % MOD;
        }

        // 使用费马小定理求分母的模逆元,将除法转换为乘法
        return (numerator * quickPow(denominator, MOD - 2n, MOD)) % MOD;
    }

    /**
     * 计算异或和之和的主函数
     */
    function xorSumSum(nums) {

        // 统计每位1的个数,最多考虑64位
        const cnt = new Array(64).fill(0n);

        for (const num of nums) {
            let temp = num;
            // 处理BigInt的二进制位
            for (let k = 0; k < 64; k++) {
                if (temp & 1n) {
                    cnt[k]++;
                }
                temp = temp >> 1n;
                if (temp === 0n) break;
            }
        }

        let ans = 0n;
        let base = 1n; // 2^k,使用BigInt

        for (let k = 0; k < 64; k++) {
            const c1 = cnt[k]; // 当前位为1的个数
            const c0 = n - c1; // 当前位为0的个数

            // 计算两种情况的三元组数量
            const case1 = nCr(c1, 3n); // 三个1的情况
            const case2 = (nCr(c0, 2n) * c1) % MOD; // 一个1和两个0的情况

            const triples = (case1 + case2) % MOD;
            ans = (ans + base * triples) % MOD;

            base = (base * 2n) % MOD; // 更新位权重
        }

        return Number(ans); // 最终结果在Number安全范围内,可转换回Number
    }

    console.log(xorSumSum(arr)); // 输出: 10
})();