1 条题解
-
0
这道题是一道经典的**按位贡献(位运算拆分)**问题。
解题思路:
异或运算(XOR)的性质是:相同为0,不同为1。
我们可以分开计算二进制每一位对答案的贡献。 对于第 位(权值为 ):
- 设数组中这一位为 1 的数字个数为
cnt1 - 那么这一位为 0 的数字个数即为
cnt0 = N - cnt1 - 要使两个数异或后第 k 位为 1,必须一个数是 0,另一个数是 1。
- 能够组成这样不同数对的组合数为
cnt0 * cnt1。
因此,第 位对总和的贡献为:。 将二进制每一位的贡献累加起来,就是最终答案。
#include <bits/stdc++.h> #define int long long using namespace std; int T = 1; const int N = 3e5 + 1, B = 60;//坏习惯,考场上记得多加点 const int MOD = 1e9 + 7; int n; int arr[N]; //慢速乘(也叫快速乘),防止溢出,顺便装一下,直接使用乘即可 int MulSlowly(int a, int b) { if (a == 0 || b == 0) return 0; int ans = 0; while (b) { if (b & 1) { ans = (ans + a) % MOD; } a = (a + a) % MOD; b >>= 1; } return ans; } void Solve() { cin >> n; for (int i = 1; i <= n; i++) { cin >> arr[i]; } int ans = 0; for (int k = 0; k <= B; k++) { int cnt1 = 0; for (int j = 1; j <= n; j++) { if ((1ll << k) & arr[j]) { cnt1++; } } int cnt0 = n - cnt1; ans = (ans + MulSlowly(MulSlowly(cnt0, cnt1), (1ll << k))) % MOD; } cout << ans; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); while (T--) { Solve(); } return 0; } - 设数组中这一位为 1 的数字个数为
- 1
信息
- ID
- 1827
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 普及+/提高-
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者