有一个 n × m n\times m n×m的网格,第 i i i行第 j j j列的格子我们记作 ( i , j ) (i,j) (i,j)。每个格子上都有一个数字, ( i , j ) (i,j) (i,j)上的数字为 a i , j a_{i,j} ai,j。你现在在 ( 1 , 1 ) (1,1) (1,1),你想走到 ( n , m ) (n,m) (n,m)处签到,每次你可以走到上下左右四个相邻的格子中的一个,当然,你不能走出网格。你现在的心情值为 a 1 , 1 a_{1,1} a1,1,你的心情飘忽不定,你每走一步,你的心情值就会异或上走到的格子上的数字。你希望你签到的时候心情最好,为此你可以任意绕远路,甚至可以走到签到处的时候暂时不签到。请你求出最大的心情值。
第一行两个正整数 n , m n,m n,m。
接下来 n n n行,每行 m m m个非负整数,其中第 i i i行第 j j j个整数表示 a i , j a_{i,j} ai,j。
输出一个整数,表示答案。
2 2
1 2
3 4
7
对于 30 % 30\% 30%的数据, n , m ≤ 4 n,m\leq 4 n,m≤4
对于另外 30 % 30\% 30%的数据, n , m ≤ 100 , a i , j ≤ 1000 n,m\leq 100,a_{i,j}\leq 1000 n,m≤100,ai,j≤1000
对于 100 % 100\% 100%的数据, n , m ≤ 500 , a i , j ≤ 1 0 9 n,m\leq 500,a_{i,j}\leq 10^9 n,m≤500,ai,j≤109
前置知识:线性基
首先,因为可以到签到点而不签到,那么沿任意一条路到达签到点后,对于点 ( i , j ) (i,j) (i,j),我们可以沿任意一条路走到点 ( i , j ) (i,j) (i,j),然后原路返回。那么走一次之后,心情值就异或上了 a i , j ⊕ a n , m a_{i,j}\oplus a_{n,m} ai,j⊕an,m。
如果我们不考虑 a n , m a_{n,m} an,m,那么其他的 a a a值其实是可以任意选来求异或和的。然后,我们发现选中的点的奇偶性是不变的,而从 ( 1 , 1 ) (1,1) (1,1)走到 ( n , m ) (n,m) (n,m)的路可以确定其奇偶性,那么
我们可以提前将所有不是 a n , m a_{n,m} an,m的 a i , j a_{i,j} ai,j的值异或上 a n , m a_{n,m} an,m,那么
那怎么求异或和的最大值呢?用线性基即可。
那么如何求异或和再异或 a n , m a_{n,m} an,m后的最大值呢?在线性基中,将 a n s ans ans的初始值设为 a n , m a_{n,m} an,m即可。
时间复杂度为 O ( n m log m x ) O(nm\log mx) O(nmlogmx),其中 m x mx mx为 a i , j a_{i,j} ai,j的最大值。
#include
using namespace std;
int n,m,ct,lst,ans,a[505][505],b[105],c[500005];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
lst=a[n][m];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]^=lst;
c[++ct]=a[i][j];
}
}
--ct;
for(int i=1;i<=ct;i++){
for(int j=30;j>=0;j--){
if((c[i]>>j)&1){
if(!b[j]){
b[j]=c[i];break;
}
c[i]^=b[j];
}
}
}
if((n+m)%2==0) ans=lst;
for(int i=30;i>=0;i--){
if((ans^b[i])>ans) ans=ans^b[i];
}
printf("%d",ans);
return 0;
}