每个元素都有偶数个相邻的$1$,就是每个元素和相邻元素异或起来为$0$。
显然可以高斯消元。
把$(i,j)$元素的值设为$x_{i,j}$,就有方程:
$(x_{i,j})\ xor\ (x_{i-1,j})\ xor\ (x_{i+1,j})\ xor\ (x_{i,j-1})\ xor\ (x_{i,j+1})=0 $
当然这个方程组解集不是唯一的。题目中要求不允许答案全$0$矩阵,就把高斯消元中遇到的自由元的值定为$1$,再把剩余方程中含有该自由元的常数$xor$上$1$。异或方程组还可以用$bitset$优化。
时间复杂度:$O(n^3/32)$
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <bitset>
#define poi(x,y) ((x-1)*m+y)
//poi(x,y)将二维坐标转成一个整数
const int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};
using namespace std;
inline int read(){
int x=0,y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
template<typename T>
inline T read(){
T x=0;
int y=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return y?-x:x;
}
int n,N,ans[1605];
//N是总元素个数(n*m)
bitset<1601>a[1605],rec[1605];
void Gauss(){
for(register int i=1;i<=N;++i){
int now=i;
while(!a[now][i]&&now<N)++now;
if(now!=i)swap(a[now],a[i]);
if(!a[i][i]){
//遇到自由元
a[i][N+1]=1;
for(register int j=i+1;j<=N;++j)
a[i][j]=0;
//常数赋值为1,系数赋值为0,也就是解为1
for(register int j=i+1;j<=N;++j)
if(a[j][i])a[j].flip(N+1);
//该元素的解对其他方程的影响
continue;
}
for(register int j=i+1;j<=N;++j)
if(a[j][i])a[j]^=a[i];
}
for(register int i=N;i;--i){
ans[i]=a[i][N+1];
for(register int j=i+1;j<=N;++j)
if(a[i][j])ans[i]^=ans[j];
}
}
int main(){
int n=read(),m=read();
N=n*m;
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m;++j){
for(register int k=0;k<5;++k){
int x=i+dx[k],y=j+dy[k];
if(x<1||x>n||y<1||y>m)continue;
a[poi(i,j)][poi(x,y)]=1;
}
}
}
Gauss();
for(register int i=1;i<=n;++i,pn)
for(register int j=1;j<=m;++j)
printf("%d ",ans[poi(i,j)]);
}