BZOJ4269:再见Xor(线性基)
Description
给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值。
Input
第一行一个正整数N。
接下来一行N个非负整数。
Output
一行,包含两个数,最大值和次大值。
Sample Input
3
3 5 6
3 5 6
Sample Output
6 5
HINT
100% : N <= 100000, 保证N个数不全是0,而且在int范围内
Solution
线性基查询第$k$小板子题。详情可以参考$YveH$学长的博客QwQ。
由线性基的性质可以知道,大小为$s$的线性基共有$2^s-1$种不同的异或值,我们只需要输出最大值和第$2^s-2$小的值就好了。
Code
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 int n,x,ans1,ans2,cnt,d[32],p[32]; 6 7 int main() 8 { 9 scanf("%d",&n); 10 for (int i=1; i<=n; ++i) 11 { 12 scanf("%d",&x); 13 for (int j=30; j>=0; --j) 14 if (x&(1<<j)) 15 { 16 if (!d[j]) {d[j]=x; break;} 17 x^=d[j]; 18 } 19 } 20 for (int i=30; i>=0; --i) 21 if ((ans1^d[i])>ans1) ans1^=d[i]; 22 printf("%d ",ans1); 23 for (int i=30; i>=0; --i) 24 for (int j=i-1; j>=0; --j) 25 if (d[i]&(1<<j)) d[i]^=d[j]; 26 for (int i=0; i<=30; ++i) 27 if (d[i]) p[cnt++]=d[i]; 28 int k=(1<<cnt)-2; 29 for (int i=30; i>=0; --i) 30 if (k&(1<<i)) ans2^=p[i]; 31 printf("%d\n",ans2); 32 }