题目描述:
就是给你n个数然后从中选择一些出来异或,求异或可得到的最大值
解题思路:
跟据题目可以假设答案ans=d1d2d3d4...(di代表ans的二进制位0/1)(这里不是乘法哦),从高位一直枚举到低位,检验是否可行。但如果直接检验的话,复杂度是O(2^n),显然超时。所以可以从高位枚举到低位,同时枚举检验每一位的可行性。我们可以根据这个列出方程组,这样检验可行性就成了检查截至当前的方程组是否有解。
引入:异或方程组解法(本题仅用到了判定有解,因此只要消元就行)
很多异或问题都要涉及到解异或方程组,因此首先要搞懂异或方程组的解法。
异或方程组的格式(设有n个未知数,m个方程):
a11x1 XOR a12x2 XOR ... XOR a1nxn = b1
a21x1 XOR a22x2 XOR ... XOR a2nxn = b2
……………………………………………………
am1x1 XOR am2x2 XOR ... XOR amn*xn = bm
第一阶段(消元):设置一个变量p,一开始p=1,然后,i从1到n,每次执行:<1>若在第p个及以后的方程中,至少有一个方程的xi系数为1,设为第q个方程,则先将第p、q个方程交换,然后用第p个方程去XOR后面剩下的所有xi系数为1的方程(各系数包括b都对应进行XOR运算,实际上就是矩阵初等行变换),将它们的xi系数均变成0,最后p加1;<2>否则(第p个及以后的方程中xi系数均为0),回到p-1行,col++;
最后结束的时候已经化成了阶梯型,就可以判别方程组有解还是无解。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll a[60]; ll Bits[60]; int T[60][60]; int Ma[60][60]; bool check(int n, int m, int k) { int row,col; for(row = col = 1; row <= k && col <= n; row++, col++) { if(!Ma[row][col]) for(int i = row+1; i <= k; i++) { if(Ma[i][col]) { swap(Ma[i], Ma[row]); //交换两行 break; } } if(!Ma[row][col]) { row--; continue; } for(int i = row+1; i <= k; i++) { if(Ma[i][col]) { for(int j = col; j <= m; j++) { Ma[i][j] ^= Ma[row][j]; } } } } for(int i = row; i <= k; i++) { if(Ma[i][m]) return false; } return true; } int main() { int n; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%lld",&a[i]); } Bits[1] = 1; memset(T, 0, sizeof(T)); for(int i = 2; i <= 51; i++) { Bits[i] = Bits[i-1] << 1; } for(int i = 51; i >= 1; i--) { T[i][n+1] = 1; for(int j = 1; j <= n; j++) { if((Bits[i] & a[j]) > 0) { T[i][j] = 1; } } memcpy(Ma, T, sizeof(Ma)); if(!check(n, n+1, 51)) T[i][n+1] = 0; } long long ans = 0; for(int i=1;i<=51;i++) ans += 1LL * T[i][n+1] * Bits[i]; printf("%lld\n", ans); }