题意:给你一些数,问你是否可以将它们划分红两个集合,使得这两个集合的异或和之差的绝对值最小。c++
设全部数的异或和为S,集合A的异或和为A。spa
首先,S的0的位对答案不形成影响。blog
S的最高位1,所对应的A的那一位必定能够为1,不妨设它为1。get
而后考虑后面的S的1位,尽可能使A对应的位置为0,这样才能使S xor A,即B的值最大化,最接近A。it
用线性基来进行断定,看可否将最高位到目前这位(假定目前这位是0)的这个区间用给定的数线性表出,若是能,就将这位设成0,不然,就将这位设成1。io
妈的,其实整个过程只须要取出最大的线性基,而后尽可能用较小的线性基去消掉除了最高位之外的1便可,获得的就是A!class
队友的代码:集合
#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 */