1 条题解

  • 0
    @ 2025-10-26 15:52:34
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long  
    const int mod = 1e9+7;  
    // 快速幂函数:计算 a^b % mod
    int ksm(int a, int b) {
        int res = 1;
        while (b) {
            if (b & 1) res = res * a % mod;  
            a = a * a % mod; 
            b >>= 1; 
        }
        return res % mod;
    }
    
    void solve() {
        int n; cin >> n;
        int a[n+1] = {0}; 
        for(int i = 1; i <= n; i++){
            cin >> a[i];
        }
        int q[33] = {0};  // q[j]统计第j位为1的元素个数(最多考虑33位,覆盖1e6的二进制位)
        for(int i = 1; i <= n; i++){
            for (int j = 0; j <= 32; j++){  // 遍历每一位(0到32位)
                if (a[i] >> j & 1) {  // 检查a[i]的第j位是否为1
                    q[j]++;
                }
            }
        }
    
        int ans = 0;
        for(int i = 0; i <= 32; i++){
            if(q[i]){  // 若第i位有元素为1
                ans = (ans + (ksm(2, q[i]) - 1) % mod) % mod;  // 累加该位贡献:2^m - 1
            }
        }
        cout << ans % mod << endl;
    }
    signed main() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        int T = 1;
        // cin >> T;
        while (T--)
            solve();
        return 0;
    }
    
    • @ 2025-10-26 15:57:33

      题解

      本题需计算数组所有非空子序列的 “幸运值” 之和(“幸运值” 为子序列按位与结果的二进制中 1 的个数)。由于直接枚举所有子序列会因数量级(2 ^ n -1n 可达 1e6)导致超时,故采用按位独立分析的方法,分别计算每一位对答案的贡献,最终累加得到结果。

      解题思路

      1. 按位拆分分析​:对于二进制的每一位(如第 j 位),只有当子序列中所有元素​的第 j 位均为 1 时,该子序列的按位与结果在第 j 位才为 1。因此可针对每一位单独计算其贡献。
      2. 单一位的贡献计算​:假设第 j 位有 m 个元素的该位为 1,那么能在该位产生 1 的子序列数量为 (2^m - 1)(即从这 m 个元素中选​任意非空子集​)。因此,第 j 位的贡献为 (2^m - 1)
      3. 总贡献累加​​:将所有位的贡献相加,即为所有子序列的幸运值之和。
    • @ 2025-10-26 17:48:04

      根据组合数学的二项式定理:

      • 一个集合的所有子集数量是 (2^m)(包含空集,即选 0 个元素的情况)。
      • 减去 “空集”(即不选任何元素的情况),非空子集的数量就是 (2^m - 1)
  • 1

花开堪折直须折 莫待无花空折枝

信息

ID
1155
时间
1000ms
内存
256MiB
难度
10
标签
递交数
13
已通过
1
上传者