题意:
给你n个数字,划分为两个集合,他们的异或和分别为x和y,求x+y的最大值。
题解:
原本的异或和为sum,题目可以理解成从n个数字中取出一个集合,这个集合的异或和为x,使得sum^x + x最大。那么对于sum中原本为0的位,如果x的这一位取1,sum ^ x的这一位也会取1,在两个地方都有收益,而sum原本为1的位,x这一位取0还是取1,结果这一位都只有一个1。我们可以用线性基来获得原本集合的二进制基底。但是我们发现光是从高到低,遇到sum为0就取这一位的线性基,遇到1就不管是不对的:因为虽然sum的这一位是1,但是它还有可能影响后面sum为0的位。我们要优先考虑sum中原本为0的位,使得x该位取为1,那么我们可以改变线性基的优先级,让sum中为0的优先级更高,这样sum为1的位就不会影响sum为0的位了,至此我们可以贪心。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5 + 50;
ll p[64];
int st[64];
int tot = 0;
void ins(ll x){
for(int i = 0; i < tot; ++i){
if((x>>st[i])&1){
if(p[i]) x^=p[i];
else {p[i] = x;
break;}
}
}
}
int n;
ll a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin>>n;
ll sum = 0;
for(int i = 0; i < n ; ++i) cin>>a[i], sum^=a[i];
for(int i = 60; i >= 0; --i) if(!((sum>>i)&1)) st[tot++] = i;
for(int i = 0; i < n; ++i) ins(a[i]);
ll res = 0;
for(int i = 0; i < tot; ++i)
if(!((res>>st[i])&1)) res ^= p[i];
cout<< res + (sum^res)<<endl;
}
/*
4
23 36 66 65
*/