#include using namespace std; vector cyclic_gray(int n) { if (n == 2) return {0, 1}; int p = 1; while ((p << 1) <= n) p <<= 1; if (p == n) { vector result(n); for (int i = 0; i < n; ++i) result[i] = i ^ (i >> 1); return result; } int r = n - p; vector small = cyclic_gray(r); int u = small[0], v = small[1]; int changed_bit = __builtin_ctz(u ^ v); vector base(p); for (int i = 0; i < p; ++i) { int x = i ^ (i >> 1); int bit0 = x & 1; int bitb = (x >> changed_bit) & 1; if (bit0 != bitb) x ^= 1 | (1 << changed_bit); base[i] = x ^ u; } vector result; result.reserve(n); result.push_back(u); result.push_back(p + u); for (int i = r - 1; i >= 1; --i) result.push_back(p + small[i]); result.push_back(v); for (int i = 2; i < p; ++i) result.push_back(base[i]); return result; } int bit_length(int x) { int result = 0; while ((1 << result) < x) ++result; return result; } pair, vector> optimal_bit_positions(int h, int w) { int rh = bit_length(h), rw = bit_length(w); vector bh(rh), bw(rw); for (int i = 0; i < rh; ++i) bh[i] = ((h - 1) >> (rh - 1 - i)) & 1; for (int j = 0; j < rw; ++j) bw[j] = ((w - 1) >> (rw - 1 - j)) & 1; const unsigned long long INF = numeric_limits::max(); vector> dp(rh + 1, vector(rw + 1, INF)); vector> take_h(rh + 1, vector(rw + 1, 0)); dp[rh][rw] = 0; for (int i = rh; i >= 0; --i) { for (int j = rw; j >= 0; --j) { if (i == rh && j == rw) continue; int remaining = (rh - i) + (rw - j); if (i < rh) { unsigned long long candidate = (static_cast(bh[i]) << (remaining - 1)) + dp[i + 1][j]; if (candidate < dp[i][j]) { dp[i][j] = candidate; take_h[i][j] = 1; } } if (j < rw) { unsigned long long candidate = (static_cast(bw[j]) << (remaining - 1)) + dp[i][j + 1]; if (candidate < dp[i][j]) { dp[i][j] = candidate; take_h[i][j] = 0; } } } } vector pos_h(rh), pos_w(rw); int i = 0, j = 0; for (int output_bit = rh + rw - 1; output_bit >= 0; --output_bit) { if (i < rh && (j == rw || take_h[i][j])) { pos_h[rh - 1 - i] = output_bit; ++i; } else { pos_w[rw - 1 - j] = output_bit; ++j; } } return {pos_h, pos_w}; } unsigned long long deposit_bits(int x, const vector& positions) { unsigned long long result = 0; for (int bit = 0; bit < (int)positions.size(); ++bit) { if ((x >> bit) & 1) result |= 1ULL << positions[bit]; } return result; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int h, w; cin >> h >> w; if ((h & 1) || (w & 1)) { cout << -1 << '\n'; return 0; } vector gh = cyclic_gray(h); vector gw = cyclic_gray(w); auto [pos_h, pos_w] = optimal_bit_positions(h, w); vector row(h), column(w); for (int i = 0; i < h; ++i) row[i] = deposit_bits(gh[i], pos_h); for (int j = 0; j < w; ++j) column[j] = deposit_bits(gw[j], pos_w); for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (j) cout << ' '; cout << (row[i] | column[j]); } cout << '\n'; } return 0; }