很明显是一道高斯消元解线性异或方程组。
对于一个 \(n\times m\) 的矩阵,我们给每个点编一个号,
对于第 \(i\)行,第 \(j\) 列的点,则有 \(p=(i-1)\times m+j\)。
那么与它相邻的点的编号就出来了,
分别是 \(p_1=p-m,p_2=p+m,p_3=p-1,p_4=p+1\)。
那么对于每一个点,我们都可以列出一个方程式
\[x_p\oplus x_{p_1}\oplus x_{p_2}\oplus x_{p_3}\oplus x_{p_4}=0 \]那么 \(n\times m\) 的矩阵就一共有 \(nm\) 个点,即我们需要列出一个 \(nm\) 元一次方程式组,
那这个方程组求出来的解就一定是答案吗?
不是,很明显,矩阵全部都为0也是这个方程组的一组合法解,
但题目又说了不能全为0,并且保证有解,那么就说明这个方程组并不是唯一解,
所以在跑完高斯消元后,对于那些*元,我们全部赋值为1,这样就能求出答案了。
还有一个问题,这样做的时间复杂度是 \(O((nm)^3)\) 的,
所以需要用bitset优化一下,就可以 \(O((nm)^2)\) 过了
不过似乎优化了还要慢一些
代码
#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;
bitset<2005> a[2005];
int n, x, y;
void gauss()
{
for (int r = 1, l = 1; l <= n; l++)
{
int t = r;
for (int i = r; i <= n; i++)
if (a[i][l])
t = i;
if (!a[t][l])
continue;
swap(a[t], a[r]);
for (int i = r + 1; i <= n; i++)
if (a[i][l])
a[i] = a[i] ^ a[r];
r++;
}
for (int i = n; i >= 1; i--)
{
if (!a[i][i])
a[i][n + 1] = 1;
else
for (int j = i + 1; j <= n; j++)
a[i][n + 1] = a[i][n + 1] ^ (a[i][j] & a[j][n + 1]);
}
}
int main()
{
scanf("%d%d", &x, &y);
n = x * y;
for (int i = 1; i <= x; i++)
{
for (int j = 1; j <= y; j++)
{
int p = (i - 1) * y + j;
int p1 = p - y, p2 = p + y, p3 = p - 1, p4 = p + 1;
if (i > 1) a[p][p1] = 1;
if (j > 1) a[p][p3] = 1;
if (i < x) a[p][p2] = 1;
if (j < y) a[p][p4] = 1;
a[p][p] = 1;
}
}
gauss();
for (int i = 1; i <= n; i++)
{
printf("%d ", (a[i][n + 1] ? 1 : 0));
if (i % y == 0)
printf("\n");
}
return 0;
}