Problem:
Score : 1100 points

Problem Statement

You are given an integer N.

Construct any one N-by-N matrix a that satisfies the conditions below. It can be proved that a solution always exists under the constraints of this problem.

1 \leq a_{i,j} \leq 10^{15}

a_{i,j} are pairwise distinct integers.

There exists a positive integer m such that the following holds: Let x and y be two elements of the matrix that are vertically or horizontally adjacent. Then, {\rm max}(x,y) {\rm mod} {\rm min}(x,y) is always m.

Constraints

2 \leq N \leq 500

Input

Input is given from Standard Input in the following format:

N

Output

Print your solution in the following format:

a_{1,1} ... a_{1,N}
:
a_{N,1} ... a_{N,N}

Sample Input 1

2

Sample Output 1

4 7
23 10

For any two elements x and y that are vertically or horizontally adjacent, {\rm max}(x,y) {\rm mod} {\rm min}(x,y) is always 3.

Solution in C++14 (GCC 5.4.1) (judge verdict: Runtime Error)

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <bitset>

using namespace std;
typedef long long ll;

template <typename T>//	Tはintかll
T gcd(T a, T b) {//	最大公約数
	if (a < 0) { a = -a; }
	if (b < 0) { b = -b; }
	if (a == 0) { return b; }
	if (b == 0) { return a; }
	if (a < b) {
		return gcd(a, b % a);
	}
	return gcd(b, a % b);
}
template <typename T>//	Tはintかll
T gcd(int size, T* a) {//	配列の最大公約数
	if (size <= 0 || a == NULL) { return 0; }
	T c = abs(a[0]);
	for (int i = 1; i < size; i++) {
		c = gcd(c, a[i]);
		if (c == 1) {
			break;
		}
	}
	return c;
}

template <typename T>//	Tはintかll
ll lcm(T a, T b) {//	最小公倍数
	if (a < 0) { a = -a; }
	if (b < 0) { b = -b; }
	if (a == 0) { return b; }
	if (b == 0) { return a; }
	ll x = a;
	x /= gcd(a, b);
	x *= b;
	return x;
}
template <typename T>//	Tはintかll
ll lcm(int size, T* a) {//	配列の最小公倍数
	if (size <= 0 || a == NULL) { return 0; }
	ll c = abs(a[0]);
	for (int i = 1; i < size; i++) {
		c = lcm(c, (ll)a[i]);
	}
	return c;
}

ll l_sqrt(ll n) {
	if (n <= 0) { return 0; }

	if (n > 256) {
		ll k = l_sqrt(n / 4) * 2;
		while ((k + 1) * (k + 1) <= n) { k++; }
		return k;
	}
	else {
		for (int i = 16; i >= 1; i--) {
			if (i * i <= n) { return i; }
		}
	}
	return 0;
}
class primeFactorClass {// 素因数分解をする
public:
	primeFactorClass() {
		factorNum = 0;
	}
	~primeFactorClass() {
		reset();
	}

	int factorNum;// 素因数の個数
	vector<ll> prime;// 素因数
	vector<int> degree;// 次数

	void factorize(ll n) {// 素因数分解
		reset();
		if (n < 0) { n = -n; }
		if (n <= 1) { return; }

		if (n % 2 == 0) {
			factorNum++;
			prime.push_back(2);
			int count = 0;
			while (n % 2 == 0) { count++; n /= 2; }
			degree.push_back(count);
		}

		ll M = l_sqrt(n) + 1;
		for (ll i = 3; i < M; i += 2) {
			if (n % i == 0) {
				factorNum++;
				prime.push_back(i);
				int count = 0;
				while (n % i == 0) { count++; n /= i; }
				degree.push_back(count);
				M = l_sqrt(n) + 1;
				if (n == 1) { break; }
			}
		}

		if (n != 1) {
			factorNum++;
			prime.push_back(n);
			degree.push_back(1);
		}
	}

private:
	void reset() {
		factorNum = 0;
		prime.clear();
		degree.clear();
	}
};

vector<ll> v;
void func(primeFactorClass& p, ll x, int depth) {
	if (depth == p.prime.size()) {
		if (x == 1) { return; }
		v.push_back(x);
	}
	else {
		for (int i = 0; i <= p.degree[depth]; i++) {
			func(p, x, depth + 1);
			x *= p.prime[depth];
		}
	}
}

int main() {
	ll bignum = 128LL * 243LL * 125LL * 49LL * 11LL * 13LL * 17LL * 19LL * 23LL;
	primeFactorClass p; p.factorize(bignum);
	func(p, 1, 0);

	int N; cin >> N;
	ll** ans = new ll * [N];
	int c = 0;
	for (int i = 0; i < N; i++) {
		ans[i] = new ll[N];
		for (int j = 0; j < N; j++) {
			if ((i + j) % 2 == 0) { ans[i][j] = bignum; }
			else {
				ans[i][j] = v[c];
				c++;
			}
		}
	}

	set<ll> st;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if ((i + j) % 2 == 0) {
				ll c = 1;
				if (i > 0) { c = lcm(c, ans[i - 1][j]); }
				if (j > 0) { c = lcm(c, ans[i][j - 1]); }
				if (i < N - 1) { c = lcm(c, ans[i + 1][j]); }
				if (j < N - 1) { c = lcm(c, ans[i][j + 1]); }
				ll d = c;
				while (st.find(d) != st.end()) {
					d += c;
				}
				st.insert(d);
				ans[i][j] += d + 1;
			}
		}
	}

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cout << ans[i][j] << " ";
		}
		cout << endl;
	}

	return 0;
}