abc141_f
题意简述:
给定一个长度为 \(n\) 的序列
要你把这个序列划分成两个集合
最后答案等于第一个集合中所有元素的异或和(\(xor-sum\))加上第二个集合中所有元素的异或和
最大化答案
正解 :
一般看到位运算都会先想到把每一位分开考虑
假如这一位有奇数个 \(1\) ,那么无论怎么拆分成两个集合这一位始终有 \(1\) 的贡献
所以先把奇数个 \(1\) 的贡献给算出来,不加以考虑
考虑这一位有偶数个 \(1\) 怎么做
假如这一位有偶数个 \(1\) ,那么这一位的所有数异或起来结果肯定是 \(0\)
设分成两个集合之后,两个集合不考虑奇数个 \(1\) 的位个话,异或和分别为 \(x_1\ x_2\)
有 \(x_1\ xor\ x_2\) 等于 \(0\),\(That's\ to\ say:x_1=x_2\)
那么只要让其中一个数最大,另一个数会等于这个数,答案也就是最大的
这一步可以用线性基做,时间复杂度\(O(nlogn)\)
\[ ans = \sum_{i = 0}^{59} [cnt_i\ mod\ 2 == 1]\times2^i + 2\times x_{max} \]
Code:
#include <bits/stdc++.h>
#define MAX 100005
#define bit(x) (1ll << x)
using namespace std;
int n;
int cnt[64];
long long a[MAX], ans;
inline long long Rd() {
long long x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
struct linear_base {
long long u[60];
inline void insert(long long val) {
for(int i = 59; i >= 0; --i) {
if(val & bit(i)) {
if(u[i]) val ^= u[i];
else {
u[i] = val;
return;
}
}
}
}
inline long long query() {
long long res = 0;
for(int i = 59; i >= 0; --i)
if((res ^ u[i]) > res) res ^= u[i];
return res;
}
}lsk;
int main() {
n = Rd();
for(int i = 1; i <= n; ++i) {
a[i] = Rd();
for(int j = 59; j >= 0; --j)
if(a[i] & bit(j)) ++cnt[j];
}
for(int i = 59; i >= 0; --i) {
if(cnt[i] & 1) {
ans += bit(i);
for(int j = 1; j <= n; ++j) {
if(a[j] & bit(i)) {
a[j] ^= bit(i);
}
}
}
}
for(int i = 1; i <= n; ++i) lsk.insert(a[i]);
cout << ans + 2ll * lsk.query() << endl;
return 0;
}