这道题是一道经典的**按位贡献(位运算拆分)**问题。

解题思路:

异或运算(XOR)的性质是:相同为0,不同为1

我们可以分开计算二进制每一位对答案的贡献。 对于第 kk 位(权值为 2k2^k):

  • 设数组中这一位为 1 的数字个数为 cnt1
  • 那么这一位为 0 的数字个数即为 cnt0 = N - cnt1
  • 要使两个数异或后第 k 位为 1,必须一个数是 0,另一个数是 1。
  • 能够组成这样不同数对的组合数为 cnt0 * cnt1

因此,第 kk 位对总和的贡献为:cnt0cnt12kcnt0 · cnt1 · 2^k。 将二进制每一位的贡献累加起来,就是最终答案。

#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