[Luogu P3164] [BZOJ 3503] [CQOI2014]和諧矩陣
阿新 • • 發佈:2018-11-25
洛谷傳送門
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("");
}
}