#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp> 
using namespace __gnu_pbds;
using namespace std;

typedef long long int lli;
#define int lli
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<lli> vli;
typedef vector<pii> vii;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> OrderedSet;

const int MOD	= 1e9 + 7;
const double PI = acos(-1.0);

#define fastio			ios_base::sync_with_stdio(0);cin.tie(0)
#define sz(a) int((a).size())
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(c) (c).begin(),(c).end()
#define present(c,x) ((c).find(x) != (c).end())
#define cpresent(c,x) (find(all(c),x) != (c).end())
#define rep(i, n)    for(int i = 0; i < (n); ++i)
#define repA(i, a, n)  for(int i = a; i <= (n); ++i)
#define repD(i, a, n)  for(int i = a; i >= (n); --i)
#define endl "\n"
#define error(x) cerr << #x << " = " << (x) << endl
#define errorp(p) cerr << #p << " = " << (p.first) << ", " << (p.second) << endl

template<typename T> T gcd(T a, T b){return(b?__gcd(a,b):a);}
template <typename T> T lcm(T a, T b){return (a*b)/gcd(a,b); }

struct node{
    lli data;

    void assign(lli val){
        data = val;
    }
}typedef node;

const int MAXN = 1002;

vector<node> seg[MAXN];
int N;
vli arr;

//Complexity: O(1)
//Stores what info. segment[i..j] should store
node merge(node &left, node &right){
    node temp;
    temp.data = left.data + right.data;
    return temp;
}

//Complexity: O(n)
void build(int segNum, int id = 1, int l = 0, int r = N){
    vector<node> &sg = seg[segNum];
    if(r - l < 2){
        //base case : leaf node information to be stored here
        sg[id].assign(1);
        return;
    }

    int mid = (l + r) / 2;
    int left = 2 * id, right = left + 1;
    build(segNum, left, l, mid);
    build(segNum, right, mid, r);
    sg[id] = merge(sg[left], sg[right]);
}

//Complexity: O(log n)
void update(int segNum, int p, int y, int id = 1, int l = 0, int r = N){
    vector<node> &sg = seg[segNum];
    if(r - l < 2){ 
        //base case : leaf node information to be stored here
        sg[id].assign(y);
        return;
    }

    int mid = (l + r) / 2;
    int left = 2 * id, right = left + 1;
    if(p < mid){
        update(segNum, p, y, left, l, mid);
    }else{
        update(segNum, p, y, right, mid, r);
    }
    sg[id] = merge(sg[left], sg[right]);
}

//Complexity: O(log n)
node query(int segNum, int x, int y, int id = 1, int l = 0, int r = N){
    vector<node> &sg = seg[segNum];
    if(r <= x || y <= l){ // No overlap, return useless
        node temp;
        temp.assign(0);
        return temp;
    }

    if(x <= l && r <= y){ // overlap
        return sg[id];
    }

    int mid = (l + r) / 2;
    int left = 2 * id, right = left + 1;
    node a = query(segNum, x,  y, left, l, mid);
    node b = query(segNum, x, y, right, mid, r);
    return merge(a, b);
}

signed main(){
    #ifdef DEBUG
		freopen("test", "r", stdin);
	#endif
    fastio;
    
    cin >> N;
    int n2 = N * N;
    vi perm(n2);
    rep(i, n2){
        cin >> perm[i];
        perm[i]--;
    }

    rep(i, 2 * N){
        seg[i].resize(4 * N);
        build(i);
    }
    // error(n2);

    int ans = 0;
    rep(i, n2){
        int row = perm[i] / N;
        int col = perm[i] % N;
        int rhate = query(row, 0, col).data;
        int chate = query(N + col, 0, row).data;
        int rtot = seg[row][1].data;
        int ctot = seg[N + col][1].data;
        // error(row);
        // error(col);
        // error(rhate);
        // error(chate);
        // error(rtot);
        // error(ctot);
        // cout << endl;

        ans += min({rhate, chate, rtot - 1 - rhate, ctot - 1 - chate});
        // error(ans);
        update(row, col, 0);
        update(N + col, row, 0);
    }

    cout << ans << endl;

    return 0;
}
