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: Accepted)

#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <set>

using namespace std;

typedef long long ll;

ll gcd (ll p, ll q) {
  if (q == 0) return p;
  return gcd(q, p % q);
}

ll lcm (ll p, ll q) {
  ll gc = gcd(p, q);
  p /= gc;
  return p * q;
}

vector<ll> transf (vector<ll> v) {
  vector<ll> u;
  while ((int) v.size() > (int) u.size()) {
    ll x = v.back();
    v.pop_back();
    u.push_back(x);
  }

  vector<ll> ans;
  for (int i = 0; i < (int) max(u.size(), v.size()); i++) {
    if (i < (int) u.size()) ans.push_back(u[i]);
    if (i < (int) v.size()) ans.push_back(v[i]);
  }

  return ans;
}

const int MAX_P = 1e5 + 5;
const int MAX_N = 505;

int sieve [MAX_P];
ll grid [MAX_N][MAX_N];
int ni [4] = {1, 0, -1, 0};
int nj [4] = {0, 1, 0, -1};

int main () {
  vector<int> primes;
  for (int i = 2; i < MAX_P; i++) {
    if (!sieve[i]) {
      if (i > 7) primes.push_back(i);
      for (int j = i; j < MAX_P; j += i) {
        sieve[j] = 1;
      }
    }
  }
  
  int n;
  cin >> n;

  int ptr = 0;
  vector<ll> rowpot;
  vector<ll> colpot;
  while ((int) rowpot.size() < (n + 20) / 2) {
    rowpot.push_back(primes[ptr]);
    ptr++;
    colpot.push_back(primes[ptr]);
    ptr++;
  }

  rowpot = transf(rowpot);
  colpot = transf(colpot);

  vector<ll> rows;
  vector<ll> cols;
  int sgn = 0;
  for (ll p : rowpot) {
    rows.push_back(p);
    if (sgn) {
      rows.push_back(2 * p);
    } else {
      rows.push_back(5 * p);
    }
    sgn = !sgn;
  }

  sgn = 0;
  for (ll q : colpot) {
    cols.push_back(q);
    if (sgn) {
      cols.push_back(3 * q);
    } else {
      cols.push_back(7 * q);
    }
    sgn = !sgn;
  }

  for (int i = 0; i <= n + 1; i++) {
    for (int j = 0; j <= n + 1; j++) {
      grid[i][j] = 1;
    }
  }

  for (int i = 0; i <= n + 1; i++) {
    for (int j = 0; j <= n + 1; j++) {
      if ((i + j) % 2 == 0) {
        grid[i][j] = rows[i] * cols[j];
      }
    }
  }

  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      if ((i + j) % 2 == 1) {
        for (int k = 0; k < 4; k++) {
          grid[i][j] = lcm(grid[i][j], grid[i + ni[k]][j + nj[k]]);
        }
        grid[i][j]++;
      }
    }
  }

  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      cout << grid[i][j] << " ";
    }
    cout << '\n';
  }
}