#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace atcoder; typedef long long ll; #define rep(i, n) for (int i = 0; i < (int)(n); i++) #define repr(i, n) for (int i = (int)(n) - 1; i >= 0; i--) #define repk(i, k, n) for (int i = k; i < (int)(n); i++) #define all(v) v.begin(), v.end() #define mod1 1000000007 #define mod2 998244353 #define mod3 100000007 #define vi vector #define vs vector #define vc vector #define vl vector #define vb vector #define vvi vector> #define vvc vector> #define vvl vector> #define vvb vector> #define vvvi vector>> #define vvvl vector>> #define pii pair #define pil pair #define pli pair #define pll pair #define vpii vector> #define vpll vector> #define vvpii vector>> #define vvpll vector>> template void debug(T e) { cerr << e << endl; } template void debug(vector &v) { rep(i, v.size()) { cerr << v[i] << " "; } cerr << endl; } template void debug(vector> &v) { rep(i, v.size()) { rep(j, v[i].size()) { cerr << v[i][j] << " "; } cerr << endl; } } template void debug(vector> &v) { rep(i, v.size()) { cerr << v[i].first << " " << v[i].second << endl; } } template void debug(set &st) { for (auto itr = st.begin(); itr != st.end(); itr++) { cerr << *itr << " "; } cerr << endl; } template void debug(multiset &ms) { for (auto itr = ms.begin(); itr != ms.end(); itr++) { cerr << *itr << " "; } cerr << endl; } template void debug(map &mp) { for (auto itr = mp.begin(); itr != mp.end(); itr++) { cerr << itr->first << " " << itr->second << endl; } } void debug_out() { cerr << endl; } template void debug_out(Head H, Tail... T) { cerr << H << " "; debug_out(T...); } using mint = modint998244353; void debug_mint1(vector &vec) { for (int i = 0; i < vec.size(); i++) { cerr << vec[i].val() << " "; } cerr << endl; } void debug_mint2(vector> &vec) { for (int i = 0; i < vec.size(); i++) { for (int j = 0; j < vec[i].size(); j++) { cerr << vec[i][j].val() << " "; } cerr << endl; } } bool has(ll a, ll b, ll M){ for (ll i = 0; i <= M; i++){ if ((a * i) % M == b % M) return true; if (a % M == (b * i) % M) return true; } return false; } bool validate(vector> &gs, ll H, ll W){ vector cnts(H * W + 1, false); for (ll i = 0; i < H; i++){ for (ll j = 0; j < W; j++){ if (gs[i][j] <= 0 || gs[i][j] > H * W){ return false; } cnts[gs[i][j]]++; } } rep(i, H * W){ if (cnts[i + 1] != 1) return false; } for (ll i = 0; i < H - 1; i++){ for (ll j = 0; j < W; j++){ if (!has(gs[i][j], gs[i + 1][j], H * W)) return false; } } for (ll i = 0; i < H; i++){ for (ll j = 0; j < W - 1; j++){ if (!has(gs[i][j], gs[i][j + 1], H * W)) return false; } } return true; } vector gray_code(ll len){ vector code; for (ll i = 0; i < (1 << len); i++){ code.push_back(i ^ (i >> 1)); } return code; } int main(){ ll H, W; cin >> H >> W; // H, W それぞれ素因数分解 vector ph; vector pw; ll H_cpy = H; ll W_cpy = W; for (ll i = 2; i * i <= H; i++){ if (H_cpy % i == 0){ ph.push_back(i); while (H_cpy % i == 0) H_cpy /= i; } } if (H_cpy != 1) ph.push_back(H_cpy); for (ll i = 2; i * i <= W; i++){ if (W_cpy % i == 0){ bool inc = false; for (auto x: ph){ if (x == i) inc = true; } if (!inc) pw.push_back(i); while (W_cpy % i == 0) W_cpy /= i; } } if (W_cpy != 1){ bool inc = false; for (auto x: ph){ if (x == W_cpy) inc = true; } if (!inc) pw.push_back(W_cpy); } ll len_h = ph.size(); ll len_w = pw.size(); // グレイコードで構築 vector code_h = gray_code(len_h); vector code_w = gray_code(len_w); vector div_h; vector div_w; for (ll i = 0; i < (1 << len_h); i++){ ll val = 1; for (ll j = 0; j < len_h; j++){ if ((code_h[i] >> j) & 1){ val *= ph[j]; } } div_h.push_back(make_pair(val, H / val)); } for (ll i = 0; i < (1 << len_w); i++){ ll val = 1; for (ll j = 0; j < len_w; j++){ if ((code_w[i] >> j) & 1){ val *= pw[j]; } } div_w.push_back(make_pair(val, W / val)); } // 約数包除原理で正しい個数をカウントする vector s_div_h; vector s_div_w; rep(i, (1 << len_h)){ s_div_h.push_back(div_h[i].first); } rep(i, (1 << len_w)){ s_div_w.push_back(div_w[i].first); } sort(all(s_div_h)); sort(all(s_div_w)); reverse(all(s_div_h)); reverse(all(s_div_w)); for (ll i = 0; i < (1 << len_h); i++){ ll idx = -1; for (ll j = 0; j < (1 << len_h); j++){ if (s_div_h[i] == div_h[j].first){ idx = j; } } for (ll j = 0; j < (1 << len_h); j++){ if (div_h[j].first % s_div_h[i] == 0 && div_h[j].first > s_div_h[i]){ div_h[idx].second -= div_h[j].second; } } } for (ll i = 0; i < (1 << len_w); i++){ ll idx = -1; for (ll j = 0; j < (1 << len_w); j++){ if (s_div_w[i] == div_w[j].first){ idx = j; } } for (ll j = 0; j < (1 << len_w); j++){ if (div_w[j].first % s_div_w[i] == 0 && div_w[j].first > s_div_w[i]){ div_w[idx].second -= div_w[j].second; } } } vector bai_h(H); vector bai_w(W); ll now_h = 0; for (ll i = 0; i < (1 << len_h); i++){ for (ll j = 0; j < div_h[i].second; j++){ bai_h[now_h + j] = div_h[i].first; } now_h += div_h[i].second; } ll now_w = 0; for (ll i = 0; i < (1 << len_w); i++){ for (ll j = 0; j < div_w[i].second; j++){ bai_w[now_w + j] = div_w[i].first; } now_w += div_w[i].second; } vector> bais(H, vector(W)); rep(i, H){ rep(j, W) bais[i][j] = bai_h[i] * bai_w[j]; } // debug(bais); set st; rep(i, H){ rep(j, W){ st.insert(bais[i][j]); } } vector vec_bai; for (auto it = st.begin(); it != st.end(); it++){ vec_bai.push_back(*it); } vector> max_divs(H * W + 1, vector(0)); for (ll i = 1; i <= H * W; i++){ ll max_div = 0; for (ll div: vec_bai){ if (i % div == 0){ max_div = max(max_div, div); } } max_divs[max_div].push_back(i); } ll len_bai = vec_bai.size(); vector ids(H * W + 1, 0); vector> ans(H, vector(W)); for (ll i = 0; i < H; i++){ for (ll j = 0; j < W; j++){ ans[i][j] = max_divs[bais[i][j]][ids[bais[i][j]]]; ids[bais[i][j]]++; } } for (ll i = 0; i < H; i++){ for (ll j = 0; j < W; j++){ cout << ans[i][j] << " "; } cout << endl; } }