【题目大意】
给定一个非负整数序列a1,a2,,,an (1<=n<=100,ai<=1018)。要求选出其的一个非空子集,使得异或和最大。求最大异或和。
【分析】
先给出算法,再简略说明正确性。
从高到底枚举每一个二进制位L。
1.找出第L位为1的数ai,如果找到则转2,否则转4.
2.若ans的第L位为0,ans^=ai。
3.使所有第L位为1的数aj^=ai。
4.枚举下一个二进制位。
正确性:
要异或和最大,很明显就是要二进制位从高到低依次尽量填1,上述算法的1,2步就是在干这个事情。
但仅仅这样是不对的,因为第L位为1的可能不止一个数,我们一开始无法判断哪一个更优,怎么办呢?第3步就解决了这个事。
假设序列中有ai,aj,它们第L位都为1。我们先假设ai更优,将ans^=ai。然后执行第3步,aj^=ai。这样就保证了如果aj比ai更优,会在后面的操作中替换掉ai的位置。保证了正确性。
时间复杂度为O(64n2)
【代码】
/* Ciocio's Oi Template */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(a);--i)
#define ll long long
#define pf printf
#define sf scanf
#define INF (~0U>>3)
#define MAXN 110
int N;
ll A[MAXN];
void Init(){
cin>>N;
rep(i,1,N){
cin>>A[i];
}
}
void Solve(){
ll rt=0;
rrep(i,62,0)
rep(j,1,N)
if((A[j]>>i)&1){
if(!((rt>>i)&1)) rt^=A[j];
rep(k,1,N)
if((k!=j)&&((A[k]>>i)&1))
A[k]^=A[j];
A[j]=0;
}
cout<<rt<<endl;
}
int main(){
Init();
Solve();
return 0;
}