题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=275
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=98837#problem/A
题目分类:高斯消元
题意:给定n个数,从中选择任意个数,使它们的异或值最大
题目分析:把每个数用二进制表示,要使异或值最大,要让高位尽量为1,用高斯消元判断高位是不是1
1. 根据数的二进制表示,建立方程组的矩阵,结果那列置为1。
2. 从下往上高斯消元(高位放下面),如果该行有未被控制的变元,则该行的结果一定为1,且该变元控制该行。
3. 从该行往上依次消掉(异或)该变元。
4. 如果该行没有可以用来控制的变元,如果最后一列是0,则该行结果也为1,否则该行结果为0。这里能抱着已用来控制的变元的系数全是0,因为在第3步时就消掉该行以上此列的0了,后面0与0以后还是0。所以如果最后一列是0, 即该行方程也可以成立,故结果为1。
建立方程:
a11x1+a21x2……=d[1]
a12x1+a22x2……=d[2]
……
代码:
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f long long bit[100]; int a[100][110]; bool used[110]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); bit[0] = 1; for(int i = 1;i < 63;i++) bit[i] = 2*bit[i-1]; int n; long long x; while(scanf("%d",&n) == 1) { for(int i = 0;i < n;i++) { cin>>x; for(int j = 0;j < 63;j++) { if(x & bit[62-j]) a[j][i] = 1; else a[j][i] = 0; } } for(int i = 0;i < 63;i++) a[i][n] = 1; memset(used,false,sizeof(used)); long long ans = 0; for(int i = 0;i < 63;i++) { int x = -1; for(int j = 0;j < n;j++) if(a[i][j] && !used[j]) { x = j; break; } if(x == -1 && a[i][n] == 0) ans += bit[62-i]; else if(x != -1) { ans += bit[62-i]; for(int k = i+1; k < 63;k++) if(a[k][x]) { for(int j = 0;j <= n;j++) a[k][j] ^= a[i][j]; } } } cout<<ans<<endl; } return 0; }