2026牛客暑期多校2 B题思路分享
题意
给定 \(n\) 个数,分成两个集合,最大化两集合内元素异或和之和.
\(1 \le n \le 5\times 10^5\).
思路
令所有元素异或和为 \(s\),第一个集合异或和为 \(x\),则 \(ans = x+(x\oplus s)\),考虑将 \(x\) 化成一项.
根据公式 \(a+b = a\oplus b + 2(a \And b)\),\(ans = s+2(x \And (s\oplus x))\).
\(x \And (s\oplus x)\) 用真值表发现可以化成 \(x\And \sim s\),因此 \(ans = s+2(x\And \sim s)\),要最大化 \(x\And \sim s\).
因为 \((\bigoplus{a_i})\And b = \bigoplus{(a_i \And b)}\),对于所有给定的元素,全部 \(\And \sim s\) 后插入线性基,之后就是标准的线性基求最大值.
时间复杂度 \(\mathcal{O}(n\log V)\),\(V\) 是值域.
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve(){
int n;
cin >> n;
vector<int> a(n+1);
int s = 0;
for (int i=1;i<=n;i++){
cin >> a[i];
s^=a[i];
}
vector<int> f(31);
auto insert = [&](int x){
for (int i=30;i>=0;i--){
if (x>>i&1){
if (f[i]==0){
f[i] = x;
break;
}
x^=f[i];
}
}
};
int m = ((1<<30)-1)^s;
for (int i=1;i<=n;i++){
insert(a[i]&m);
}
int mx = 0;
for (int i=30;i>=0;i--){
mx = max(mx,mx^f[i]);
}
cout << s+2*mx << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号