# input import sys input = sys.stdin.readline II = lambda : int(input()) MI = lambda : map(int, input().split()) LI = lambda : [int(a) for a in input().split()] SI = lambda : input().rstrip() LLI = lambda n : [[int(a) for a in input().split()] for _ in range(n)] LSI = lambda n : [input().rstrip() for _ in range(n)] MI_1 = lambda : map(lambda x:int(x)-1, input().split()) LI_1 = lambda : [int(a)-1 for a in input().split()] mod = 998244353 inf = 1001001001001001001 ordalp = lambda s : ord(s)-65 if s.isupper() else ord(s)-97 ordallalp = lambda s : ord(s)-39 if s.isupper() else ord(s)-97 yes = lambda : print("Yes") no = lambda : print("No") yn = lambda flag : print("Yes" if flag else "No") prinf = lambda ans : print(ans if ans < 1000001001001001001 else -1) alplow = "abcdefghijklmnopqrstuvwxyz" alpup = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" alpall = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" URDL = {'U':(-1,0), 'R':(0,1), 'D':(1,0), 'L':(0,-1)} DIR_4 = [[-1,0],[0,1],[1,0],[0,-1]] DIR_8 = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]] DIR_BISHOP = [[-1,1],[1,1],[1,-1],[-1,-1]] prime60 = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59] sys.set_int_max_str_digits(0) # sys.setrecursionlimit(10**6) # import pypyjit # pypyjit.set_param('max_unroll_recursion=-1') from collections import defaultdict,deque from heapq import heappop,heappush from bisect import bisect_left,bisect_right DD = defaultdict BSL = bisect_left BSR = bisect_right def inv_gcd(a, b): a = a % b if a == 0: return (b, 0) s = b t = a m0 = 0 m1 = 1 while t: u = s // t s -= t * u m0 -= m1 * u s, t = t, s m0, m1 = m1, m0 if m0 < 0: m0 += b // s return (s, m0) def inv_mod(x, m): assert 1 <= m z = inv_gcd(x, m) assert z[0] == 1 return z[1] def crt(r, m): assert len(r) == len(m) n = len(r) r0 = 0 m0 = 1 for i in range(n): assert 1 <= m[i] r1 = r[i] % m[i] m1 = m[i] if m0 < m1: r0, r1 = r1, r0 m0, m1 = m1, m0 if m0 % m1 == 0: if r0 % m1 != r1: return (0, 0) continue g, im = inv_gcd(m0, m1) u1 = m1 // g if (r1 - r0) % g: return (0, 0) x = (r1 - r0) // g % u1 * im % u1 r0 += x * m0 m0 *= u1 if r0 < 0: r0 += m0 return (r0, m0) def floor_sum(n, m, a, b): ans = 0 while True: if a < 0 or a >= m: k = a // m a = a % m if a < 0: a += m k -= 1 ans += k * n * (n - 1) // 2 if b < 0 or b >= m: k = b // m b = b % m if b < 0: b += m k -= 1 ans += k * n y_max = (a * n + b) // m if y_max == 0: break x_max = y_max * m - b ans += (n - (x_max + a - 1) // a) * y_max n, m, a, b = y_max, a, m, (a - x_max % a) % a return ans from math import isqrt from random import randint def gcd(x, y): """ x < y """ while y: x, y = y, x%y return x def is_prime(num): """ 1 <= x < 1<<64 """ if num < 4: return num > 1 if not num&1: return False d, s = num-1, 0 while not d&1: d >>= 1 s += 1 tests = (2,7,61) if num < 4759123141 else (2,325,9375,28178,450775,9780504,1795265022) for test in tests: if test >= num: return True t = pow(test, d, num) if 1 < t < num-1: for _ in range(s-1): t = t*t%num if t == num-1: break else: return False return True def find_prime(n): b = n.bit_length() - 1 b = (b >> 2) << 2 m = (1 << (b >> 3)) << 1 while True: c = randint(1, n - 1) y = 0 g = q = r = 1 while g == 1: x = y for _ in range(r): y = (y * y + c) % n k = 0 while k < r and g == 1: ys = y for _ in range(min(m, r - k)): y = (y * y + c) % n q = q * abs(x - y) % n g = gcd(q, n) k += m r <<= 1 if g == n: g = 1 y = ys while g == 1: y = (y * y + c) % n g = gcd(abs(x - y), n) if g == n: continue if is_prime(g): return g elif is_prime(n // g): return n // g else: n = g def _primefactor(n): result = [] for p in range(2, 500): if p * p > n: break c = 0 while n%p == 0: n //= p c += 1 if c: result.append(p) while n > 1 and not is_prime(n): p = find_prime(n) while n % p == 0: n //= p result.append(p) if n > 1: result.append(n) return result def primefact(n, deduplicate = True): if deduplicate == False: return _primefactor(n) result = dict() for p in range(2, 500): if p * p > n: break c = 0 while n%p == 0: n //= p c += 1 if c: result[p] = c while n > 1 and not is_prime(n): p = find_prime(n) c = 0 while n % p == 0: n //= p c += 1 result[p] = c if n > 1: result[n] = 1 return result def divisors_naive(n): divs_small, divs_big = [], [] i = 1 while i*i <= n: if n % i == 0: divs_small.append(i) if i != n//i: divs_big.append(n//i) i += 1 return divs_small + divs_big[::-1] def divisors(n): if n == 1: return [1] if n <= 100_000_000: # 10 ** 8 return divisors_naive(n) pf = primefact(n) ps = list(pf.keys()) es = list(pf.values()) us = [p ** e for p,e in zip(ps, es)] l = len(es) nes = [0] * (l + 1) r = 1 res = [1] while True: nes[0] += 1 for i in range(l): if nes[i] > es[i]: if i+1 == l: res.sort() return res nes[i] = 0 nes[i+1] += 1 r //= us[i] else: r *= ps[i] break res.append(r) def totient(n): """ totient(n) = #{ m | (m,n) = 1, 1 <= m <= n } """ pf = _primefactor(n) for p in pf: n //= p n *= p - 1 return n def mobius(n): pf = primefact(n) r = 1 for p,e in pf.items(): if e >= 2: return 0 r *= -1 return r def primitive_root(p): """ p : prime """ if p == 2: return 1 r = p - 1 tests = [] for q in range(2, 500): if q * q > r: break if r % q == 0: while r % q == 0: r //= q tests.append((p - 1) // q) while r > 1 and not is_prime(r): q = find_prime(r) while r % q == 0: r //= q tests.append((p - 1) // q) if r > 1: tests.append((p - 1) // r) res = 2 while True: for test in tests: if pow(res, test, p) == 1: break else: return res res = randint(3, p - 2) def check(h, w, a): m = h * w for i in range(h): for j in range(w - 1): f = 0 for x in range(1, m): if a[i][j] * x % m == a[i][j+1]: f = 1 if a[i][j] == a[i][j+1] * x % m: f = 1 if f == 0: return False for i in range(h - 1): for j in range(w): f = 0 for x in range(1, m): if a[i][j] * x % m == a[i+1][j]: f = 1 if a[i][j] == a[i+1][j] * x % m: f = 1 if f == 0: return False return True from math import gcd """ gcd が割り切れば ok 素数を一つだけ変える """ def calc(ps): now = [tuple()] for x in ps: # x = p ** e nxt = [] for y in range(x): c = now if y & 1 else reversed(now) for v in c: nxt.append(v + (y,)) now = nxt return now def solve(h, w): m = h * w pf = primefact(m) # これのべき ph = [] pw = [] pm = [] for p, e in pf.items(): eh = 0 h_ = h while h_ % p == 0: h_ //= p eh += 1 ew = e - eh ph.append(p ** eh) pw.append(p ** ew) pm.append(p ** e) ans = [[0] * w for i in range(h)] # 列ごとに r = calc(ph[:]) c = calc(pw[:]) # print(r) # print(c) for i in range(h): for j in range(w): p = [] q = [] # 素数ごとにつくっておいて cht でもどす for k in range(len(pf)): p.append((r[i][k] + ph[k] * c[j][k]) % pm[k]) q.append(pm[k]) ans[i][j] = crt(p, q)[0] if ans[i][j] == 0: ans[i][j] = m return ans h, w = MI() ans = solve(h, w) for e in ans: print(*e) # for h in range(2, 5): # for w in range(2, 5): # ans = solve(h, w) # check(h, w, ans)