您的位置:首页 > 其它

【bzoj4296】再见Xor

2016-11-21 13:05 183 查看

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 }


 

 
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: