【bzoj4296】再见Xor
4269: 再见Xor
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 176 Solved: 107
[Submit][Status][Discuss]
Description
给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值。
Input
第一行一个正整数N。
接下来一行N个非负整数。
Output
一行,包含两个数,最大值和次大值。
Sample Input
3
3 5 6
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 }