【bzoj4296】再见Xor

4269: 再见Xor

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 176  Solved: 107
[Submit][Status][Discuss]

Description

给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值。

Input

第一行一个正整数N。
接下来一行N个非负整数。

Output

一行,包含两个数,最大值和次大值。

Sample Input

3
3 5 6

Sample Output

6 5
 
 
 
【题解】
这算是一道高斯消元求线性基的模板题,我尽量讲得详细点。
 
首先把每个数拆成二进制的形式,用矩阵表示。
 
如样例:
 
    0 1 1
    1 0 1
    1 1 0
 
然后高斯消元:
 
    0 1 1  交换前2行     1 0 1  处理2和3行    1 0 1    处理第3行        1 0 1
    1 0 1    =======>   0 1 1   ========>  0 1 1   =======>   0 1 1
    1 1 0             1 1 0            0 1 1          0 0 0
 
此时只能保证第二行二进制第二位为1,记录temp=2
 
然后把矩阵的前temp行求异或和,就是最大值ans,然后ans^a[temp]就是次大值。
 
可以yy一下,或者自己动手推推。
 
 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<ctime>
 7 #include<algorithm>
 8 using namespace std;
 9 #define MAXN 100010
10 int n,ans,a[MAXN];
11 inline int read()
12 {
13     int x=0,f=1;  char ch=getchar();
14     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
15     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
16     return x*f;
17 }
18 void guess()
19 {
20     int temp=0;
21     for(int i=(1<<30),j;i;i>>=1)//枚举2进制每一位
22     {
23         for(j=temp+1;j<=n;j++)  if(a[j]&i)  break;//找到当前二进制位上是1的第一个数
24         if(j>n)  continue;//找不到,继续
25         swap(a[++temp],a[j]);//高斯消元固有的
26         for(int j=1;j<=n;j++)  if(j!=temp&&(a[j]&i))  a[j]^=a[temp];//处理其他行
27     }
28     for(int i=1;i<=temp;i++)  ans^=a[i];
29     printf("%d %d\n",ans,ans^a[temp]);
30 }
31 int main()
32 {
33     //freopen("cin.in","r",stdin);
34     //freopen("cout.out","w",stdout);
35     n=read();
36     for(int i=1;i<=n;i++)  a[i]=read();
37     guess();
38     return 0;
39 }

 

 
 
 
posted @ 2016-10-09 20:51  chty  阅读(283)  评论(0编辑  收藏  举报