首页 > 试题广场 >

小红的相等数组

[编程题]小红的相等数组
  • 热度指数:256 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红希望你构造一个长度为 n 的数组,满足:
1. 数组中的每个元素 a_i 满足 0 \leq a_i < 2^k
2. 数组所有元素的异或和小于等于所有元素的与和。即 a_1 \oplus a_2 \oplus \cdots \oplus a_n \leq a_1 \And a_2 \And \cdots \And a_n

小红想知道有多少种可能的方案数。

输入描述:
第一行输入两个整数 nk
1 \leq n \leq 10^5
0 \leq k \leq 10^5


输出描述:
输出一个整数,表示满足条件的数组的方案数。由于答案可能很大,请对 10^9 + 7 取模。
示例1

输入

2 2

输出

6

说明

一共有 6 种可能的方案数。分别是 [0,0], [1,1], [2,2], [3,3], [2,3], [3,2]
对于多数的位运算,通常思考方式:考虑二进制某一位的操作+是否会影响其他位。如果影响找到其“稳定点”继续寻找突破点。
当前题目是&和^的比较。我们知道^是相同为0,不同为1。那假设现在考虑第p位。
只有全为1时,&才为1,奇数个1时,^才为1。那么n考虑奇偶性
n为奇数:
    全为   1                         :&和^都为1
    奇数个1(但不全为1):&为0,^为1
    偶数个1                        :  &和^都为0
如果比p位高的高位都是满足条件的情况下,只有全1和偶数个1是满足的条件的(相等),而且高位肯定也是全是:全为1和偶数个1,不然&<^了。所以n为奇数的每一位都是独立的,那么每一位的种类有多少?2n-1 + 1,因为有n个数,且只有01选项,+1是因为全为1的情况,

n为偶数:
    全为   1                         :&为1,^为0(偶数个1)
    奇数个1(但不全为1):&为0,^为1
    偶数个1(不全为1)    :  &和^都为0
当全为1时,我们发现&比^大了,那就是说当第一个全为1的情况出现时,后面的所有位就可以随机选了,因为都满足情况。那前面的呢?只能选不全为1的偶数,这样就又都不受影响了。
最后还要考虑没有全为1的情况。计算即可。那怎么计算呢?枚举第一个全为1的位置,这样就可以计算所有情况了,且不重复。
注:为什么枚举第一个全为1的位置,就可以计算所有的情况,且不重复
假设k=2,n=2
bit 1 2      1  2
     0 1      1  x
     0 1      1  x
可以看到当第一个全为1出现在第二位时,第一位是可以随便排列的,那么就是存在了
bit 1 2
     1 1
     1 1
而不会在当第一个全为1出现在第一位时,第二位也全为1,因为这里的计算方式是:
前i-1位随便选后k-i位只能选偶数个1且全部不为1
#include <iostream>
using namespace std;

int main() {
    int n, k, mod = 1e9 + 7;
    std::cin >> n >> k;

    auto ksm = [&](int x, int y) -> int {
        if (y < 0) return 0;
        int ans = 1;
        while (y) {
            if (y & 1) ans = 1ll* ans * x % mod;
            x = 1ll* x * x % mod;
            y >>= 1;
        }
        return ans;
    };

    if (n & 1) {
        // 全1 + 偶数1,每位独立。因为当全1时,&和^都是1,偶数1,那么&和^都是0,这样就是都是的大小
        // 2^n是所有的种类,所以偶数1为2^{n-1}
        std::cout << ksm(ksm(2, n-1)+1, k) << std::endl;
        return 0;
    }

    // n为偶数时,并不是独立的,因为全为1时,&是1,^为0,那么此时后面位都可以乱选也是符合条件的;那就枚举
    int ans = 0;
    for (int i = 1; i <= k; i ++) {
        int res = 1ll * ksm(ksm(2, n), i - 1) * ksm(ksm(2, n - 1) - 1, k - i) % mod;
        ans = (ans + res) % mod;
    }
    std::cout << (ans + ksm(ksm(2, n - 1) - 1, k)) % mod << std::endl;

}


编辑于 2025-09-20 16:10:41 回复(0)