#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10, mod = 998244353;
using ordered_set = struct seg_tree {
  int n;
  vector<int> tree;
  seg_tree(int n) : n(n), tree(4 * n, 0) {}
  void update(int i, int l, int r, int p, int v) {
    if (p > r or p < l) {
      return;
    } else if (l == r) {
      tree[i] = v;
    } else {
      int mid = (l + r) / 2, lc = 2 * i, rc = lc + 1;
      update(lc, l, mid, p, v);
      update(rc, mid + 1, r, p, v);
      tree[i] = tree[lc] + tree[rc];
    }
  }
  int query(int i, int l, int r, int ql, int qr) {
    if (l > qr or ql > r) {
      return 0;
    } else if (ql <= l and r <= qr) {
      return tree[i];
    } else {
      int mid = (l + r) / 2, lc = 2 * i, rc = lc + 1;
      return query(lc, l, mid, ql, qr) + query(rc, mid + 1, r, ql, qr);
    }
  }
  void insert(int p) { update(1, 1, n, p, 1); }
  void erase(int p) { update(1, 1, n, p, 0); }
  int order_of_key(int v) { return query(1, 1, n, 1, v - 1); }
  int find(int v) { return query(1, 1, n, v, v); }
  int size() { return tree[1]; }
};
long long perm_rank(int *p, int n);
long long der_rank(int *p, int *q, int n);
long long pwr(long long x, long long e);
int p[N][N];
long long fact[N], f[N][N], d[N];
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int n;
  cin >> n;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      cin >> p[i][j];
    }
  }
  fact[0] = 1;
  for (int i = 1; i <= n; ++i) {
    fact[i] = (i * fact[i - 1]) % mod;
  }
  for (int i = 0; i <= n; ++i) {
    f[i][0] = fact[i];
    for (int j = 1; j <= i; ++j) {
      f[i][j] = (j - 1) * f[i - 1][j - 2] + (i - j) * f[i - 1][j - 1];
      f[i][j] %= mod;
    }
    d[i] = f[i][i];
  }
  long long ans = perm_rank(p[1], n) * pwr(d[n], n - 1);
  ans %= mod;
  for (int i = 1; i < n; ++i) {
    ans += der_rank(p[i], p[i + 1], n) * pwr(d[n], n - i - 1);
    ans %= mod;
  }
  cout << ans << endl;
}
long long perm_rank(int *p, int n) {
  ordered_set s(n);
  long long ans = 0;
  for (int i = 1; i <= n; ++i) {
    s.insert(p[i]);
    long long temp = (p[i] - 1) - s.order_of_key(p[i]);
    ans += temp * fact[n - i];
    ans %= mod;
  }
  return ans;
}
long long der_rank(int *p, int *q, int n) {
  ordered_set s(n), t(n);
  for (int i = 1; i <= n; ++i) {
    t.insert(i);
  }
  long long ans = 0;
  for (int i = 1; i <= n; ++i) {
    s.insert(q[i]);
    long long tot = (q[i] - 1) - s.order_of_key(q[i]);
    if (p[i] < q[i] and !s.find(p[i])) {
      --tot;
    }
    t.erase(p[i]);
    long long c1 = t.order_of_key(q[i]);
    ans += c1 * f[n - i][t.size() - 1];
    ans += (tot - c1) * f[n - i][t.size()];
    ans %= mod;
    t.erase(q[i]);
  }
  return ans;
}
long long pwr(long long x, long long e) {
  long long res = 1;
  while (e) {
    if (e & 1) {
      res = (res * x) % mod;
    }
    x = (x * x) % mod;
    e /= 2;
  }
  return res;
}
