题意:给你一些数,问你是否能够将它们划分成两个集合,使得这两个集合的异或和之差的绝对值最小。
设所有数的异或和为S,集合A的异或和为A。
首先,S的0的位对答案不造成影响。
S的最高位1,所对应的A的那一位一定可以为1,不妨设它为1。
然后考虑后面的S的1位,尽量使A对应的位置为0,这样才能使S xor A,即B的值最大化,最接近A。
用线性基来进行判定,看能否将最高位到目前这位(假定目前这位是0)的这个区间用给定的数线性表出,如果能,就将这位设成0,否则,就将这位设成1。
妈的,其实整个过程只需要取出最大的线性基,然后尽量用较小的线性基去消掉除了最高位以外的1即可,得到的就是A!
队友的代码:
#include <bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for (LL i=(a);i<=(b);++i)
#define ROF(i,b,a) for (LL i=(b);i>=(a);--i)
typedef long long LL;
LL read(){
LL x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
return x*f;
}
const LL MAXN=300005;
LL n,m,q,a[MAXN],b[MAXN],c[MAXN],f[100];
int main() {
LL T=read();
while (T--) {
n=read(); m=0;
FOR(i,1,n) m^=a[i]=read();
FOR(i,1,n) a[i]&=m;
memset(f,0,sizeof(f));
FOR(i,1,n) {
ROF(j,62,0)
if ((a[i]>>j)&1) {
if (!f[j]) { f[j]=a[i]; break; }
else {
//if (a[i]<f[j]) swap(a[i],f[j]);
a[i]^=f[j];
}
}
}
LL x=-1,y=0;
ROF(i,62,0) if (f[i]) { x=i; break; }
if (x>=0) y=f[x];
//cerr<<y<<' '<<m<<endl;
ROF(i,x-1,0)
if (f[i])
if ((y>>i)&1) y^=f[i];
cout<<abs(y-(y^m))<<endl;
}
return 0;
}
/*
2
4
1 2 3 4
5
3 7 3 9 5
*/