题目大意
给一个 n × m n\times m n×m的网格,然后从 ( 1 , 1 ) (1,1) (1,1)走到 ( n , m ) (n,m) (n,m)处。每次可往上下左右四个方向走。问走过路径上的数的异或和最大是多少。(走到 ( n , m ) (n,m) (n,m)处不一定要结束)
思路:
推演发现,这题选择的数的个数的奇偶和
n
+
m
−
1
n+m-1
n+m−1的奇偶相同,而想选里面任意一个数都是没问题的。
所以考虑奇数的情况,每个数加一个很大的2次幂,这就保证了要选奇数个数。
偶数的情况就是在线性基里面多加一个由两个很大的2次幂构成的数,这就保证了这个数必须被选,然后转化为奇数的情况。
c o d e code code
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
using namespace std;
ll n, m;
ll d[61];
void add(ll x) {
for(ll i = 60; i >= 0; i --)
if(x & (1ll << i)) {
if(d[i]) x ^= d[i];
else {
d[i] = x;
break;
}
}
}
ll ans() {
ll ANS = 0;
for(ll i = 60; i >= 0; i --)
if((ANS ^ d[i]) >= ANS) ANS ^= d[i];
return ANS;
}
int main() {
freopen("xor.in", "r", stdin);
freopen("xor.out", "w", stdout);
scanf("%lld%lld", &n, &m);
for(ll i = 1; i <= n; i ++)
for(ll j = 1; j <= m; j ++) {
ll x;
scanf("%lld", &x);
add(x + (1ll << 34));
}
if((n + m - 1) % 2 == 0) {
add((1ll << 34) + (1ll << 33));
printf("%lld", ans() - ((1ll << 34) + (1ll << 33)));
}
else {
printf("%lld", ans() - (1ll << 34));
}
return 0;
}