给n个数,任选若干个,使得异或值最大
引理:
【假设集合A,其中我们将ai替换成ai xor a[j] i<>j,那么得到的新集合,这个集合中元素能xor出的值于集合A相同】
实际本题用到的是:
也就是说要ans 去异或上 A[1..n]的任意个数时,对应了一个值域A
如果你先让ans^=A[1],然后去用A[1]异或上所有A[2..n],此时用ans异或上 A[2..N]的任意个,对应的值域B = 上面的值域A
算法:
按位贪心
从高位到低位枚举二进制位D
1.找出第L位为1的数ai,如果找到则转2,否则转4
2.若ans的第L位为0,ans^=ai,若为1则不异或ai
3.使所有第L位为1的数aj^=ai。(不管2中的ans是否有异或ai)
4.枚举下一个二进制位。
void solve(ll init,int N,ll A[])
{
ll rt=0;
for (int i=62;i>=0;i--)
{
for (int j=1;j<=N;j++)
{
if((A[j]>>i)&1)
{
if(!((rt>>i)&1)) rt^=A[j];
for (int k=1;k<=N;k++)
if((k!=j)&&((A[k]>>i)&1))
A[k]^=A[j];
A[j]=0;
}
}
}
cout<<rt<<endl;
}
对于步骤2,如果选到一个第X位为1的数,如果此时ans的x位=0,则ans^=A[i],再用A[i]去异或上所有x位为1的数,最后ans的值域与异或A[i]之前的一样的(根据引理)
如果此时ans的x位为1,是否可以直接跳过?
不可以,显然算法的每一步都应该保证把所有数的X位置零,否则后面的异或操作会修改的ans的值
其次,那么按照步骤2,ans没异或A【i】,步骤3却依旧要用A【i】异或上所有 X位为1的数,是否就改变了值域了?
{
如果此时是ans异或上任意个A[i]的话,值域确实改变了!!
但是显然,如果当前ans的X位已经是1,那么我们只能在这些 X位为1的A【i】(共k个)中选取偶数个,这对应了一个值域C
于是我们把 这些X位为1的A【i】任选一个,去异或上别的所有X位为1的A【i】,再去掉A[i],此时我们剩下k-1个 X位为1的A[i]
不管我们怎么选这k-1个数,都能得到 原来的k个A[i]值异或后的结果。
也就是 在 ans的x位为1时,我们只能从X位为1的A【i】中任选偶数个A[i],在这个条件下,做完步骤3之后,ans就可以从新的k-1个A[i]中选任意个,并且对应的值域D与原来的值域C是相等的!
}
复杂度:60*n
由于每次只消一位,显然只需要消去60次
参考学习blog:http://blog.csdn.net/greatwjj/article/details/20942281