版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/83795153
洛谷传送门
BZOJ传送门
题目描述
我们称一个由 和 组成的矩阵是和谐的,当且仅当每个元素都有偶数个相邻的 。一个元素相邻的元素包括它本身,及他上下左右的 个元素(如果存在)。给定矩阵的行数和列数,请计算并输出一个和谐的矩阵。注意:所有元素为 的矩阵是不允许的。
输入输出格式
输入格式:
输入一行,包含两个空格分隔的整数 和 ,分别表示矩阵的行数和列数。
输出格式:
输出包含 行,每行 个空格分隔整数( 或 ),为所求矩阵。测试数据保证有解。
输入输出样例
输入样例#1:
4 4
输出样例#1:
0 1 0 0
1 1 1 0
0 0 0 1
1 1 0 1
说明
数据范围
解题分析
首先我们可以暴力高斯消元, 因为是异或方程组, 可以用 优化,复杂度是 , 的确能过…
然而这里有一种更优雅的写法: 我们发现只要确定第一行的元素就可以确定整个表的元素, 而整个表有合法解的必要条件为第 行元素递推出来全部为 。那么我们先 递推出第 行元素对应的第一行的元素组成, 这样就可以列出 个 元方程, 进而解出得到第一行的元素, 最后再递推一次即可。
总复杂度 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <bitset>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 45
#define ll long long
int n, m;
ll tran[MX][MX];
std::bitset <MX> mat[MX], ans[MX];
void Gauss()
{
for (R int i = 1; i <= m; ++i)
{
for (R int j = i; j <= m; ++j)
if (mat[j][i]) {std::swap(mat[j], mat[i]); break;}
if (!mat[i][i]) continue;
for (R int j = i + 1; j <= m; ++j) if (mat[j][i]) mat[j] ^= mat[i];
}
for (R int i = m; i; --i)
{
ans[1][i] = mat[i][i] ? mat[i][m + 1] : 1;
if (ans[1][i]) for (R int j = 1; j < i; ++j) if (mat[j][i]) mat[j][m + 1] = !mat[j][m + 1];
}
}
int main(void)
{
scanf("%d%d", &n, &m);
for (R int i = 1; i <= m; ++i) tran[1][i] = 1ll << i;
for (R int i = 2; i <= n + 1; ++i)
for (R int j = 1; j <= m; ++j)
tran[i][j] = tran[i - 1][j - 1] ^ tran[i - 1][j] ^ tran[i - 1][j + 1] ^ tran[i - 2][j];
for (R int i = 1; i <= m; ++i)
for (R int j = 1; j <= m; ++j) mat[i][j] = (tran[n + 1][i] >> j) & 1;
Gauss();
for (R int i = 2; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
ans[i][j] = ans[i - 1][j - 1] ^ ans[i - 1][j] ^ ans[i - 1][j + 1] ^ ans[i - 2][j];
for (R int i = 1; i <= n; ++i)
{
for (R int j = 1; j <= m; ++j) printf("%d ", (int)ans[i][j]);
puts("");
}
}