#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
template <typename T>
istream& operator>>(istream& in, vector<T>& a) {
  for (auto& i : a) in >> i;
  return in;
}
template <typename T>
ostream& operator<<(ostream& out, vector<T>& a) {
  for (auto& i : a) out << i << " ";
  return out;
}
template <typename T, typename U>
void chkmin(T& a, U b) {
  if (a > b) a = b;
}
template <typename T, typename U>
void chkmax(T& a, U b) {
  if (a < b) a = b;
}
class Dsu {
 private:
  int n;
  vector<int> p, sz;

 public:
  Dsu(int _n) {
    n = _n;
    p.resize(n, -1);
    sz.resize(n, 1);
  }
  int get(int v) {
    if (p[v] == -1) return v;
    return p[v] = get(p[v]);
  }
  void unite(int v, int u) {
    v = get(v), u = get(u);
    if (v == u) return;
    if (sz[v] > sz[u]) swap(v, u);
    p[v] = u;
    sz[u] += sz[v];
  }
};
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0);
  int n;
  cin >> n;
  vector<int> ord(n * n);
  for (int i = (int)0; i < (int)n * n; i++) {
    cin >> ord[i];
    ord[i]--;
  }
  vector<vector<int>> gr(n * n);
  vector<int> dst(n * n);
  auto convert = [&](int x, int y) -> int { return x * n + y; };
  vector<int> dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
  auto on_grid = [&](int x, int y) -> bool {
    return 0 <= x && x < n && 0 <= y && y < n;
  };
  for (int i = (int)0; i < (int)n; i++) {
    for (int j = (int)0; j < (int)n; j++) {
      dst[convert(i, j)] = min({i, (n - 1) - i, j, (n - 1) - j});
      for (int k = (int)0; k < (int)4; k++) {
        int x = i + dx[k], y = j + dy[k];
        if (on_grid(x, y)) gr[convert(i, j)].push_back(convert(x, y));
      }
    }
  }
  Dsu sets(n * n);
  auto bfs = [&](int s) -> void {
    deque<int> q = {s};
    while (!q.empty()) {
      int v = q.front();
      q.pop_front();
      for (int u : gr[v])
        if (dst[v] + 1 < dst[u]) {
          dst[u] = dst[v] + 1;
          q.push_back(u);
        }
    }
  };
  auto unite = [&](int v, int u) -> void {
    if (sets.get(v) == sets.get(u)) return;
    v = sets.get(v), u = sets.get(u);
    if (gr[v].size() > gr[u].size()) swap(v, u);
    for (auto i : gr[v]) gr[u].push_back(i);
    chkmin(dst[u], dst[v]);
    sets.unite(v, u);
    bfs(u);
  };
  vector<bool> used(n * n);
  int ans = 0;
  for (int i = (int)0; i < (int)n * n; i++) {
    int x = ord[i] / n, y = ord[i] % n;
    for (int k = (int)0; k < (int)4; k++) {
      int nx = x + dx[k], ny = y + dy[k];
      if (on_grid(nx, ny) && used[convert(nx, ny)])
        unite(ord[i], convert(nx, ny));
    }
    ans += dst[sets.get(ord[i])];
    used[convert(x, y)] = true;
  }
  cout << ans;
  return 0;
}
