#include <bits/stdc++.h>
using namespace std;
const double PI = 2 * acos(0.0);
const string DIGITS = "0123456789";
const string ALPH = "abcdefghijklmnopqrstuvwxyz";
template <class T>
ostream &operator<<(ostream &out, vector<T> &a) {
  out << "{";
  for (int i = 0; i < int(((int)((a).size()))); ++i)
    out << a[i] << vector<string>{", ", "}"}[i + 1 == ((int)((a).size()))];
  return out;
}
void smain();
signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cout << setprecision(12) << fixed;
  smain();
}
bool check(vector<int> &a) {
  for (int i = 0; i < int(((int)((a).size()))); ++i)
    if (a[i] == i + 1) return 0;
  return 1;
}
long long brute(int n) {
  vector<int> a(n);
  for (int i = 0; i < int(n); ++i) a[i] = i + 1;
  long long ret = 0;
  do {
    ret += check(a);
    if (check(a)) cout << a << endl;
  } while (next_permutation(a.begin(), a.end()));
  return ret;
}
const long long M = 998244353;
long long pw(long long a, long long n) {
  long long ret = 1;
  while (n) {
    if (n & 1) ret = (ret * a) % M;
    a = (a * a) % M;
    n >>= 1;
  }
  return ret;
}
const int N = 2009;
long long fact[N], inv[N];
int lazy[N][N];
void init() {
  fact[0] = inv[0] = 1;
  for (int i = 1; i < N; ++i) {
    fact[i] = fact[i - 1] * i % M;
    inv[i] = pw(fact[i], M - 2);
  }
  for (int i = 0; i < int(N); ++i) fill(lazy[i], lazy[i] + N, -1);
}
inline long long nCr(int n, int k) {
  return fact[n] * inv[k] % M * inv[n - k] % M;
}
long long get_valid(int n, int k = -1) {
  if (k == -1) k = n;
  int ret = 0;
  for (int i = 0; i <= k; ++i) {
    long long cur = nCr(k, i) * fact[n - i] % M;
    if (i & 1) cur = M - cur;
    ret = (ret + cur) % M;
  }
  return ret;
}
struct Fenwik {
  int t[N];
  Fenwik() { fill(t, t + N, 0); }
  inline void upd(int i, int v) {
    for (; i < N; i += i & -i) t[i] += v;
  }
  inline int get(int i) {
    int ret = 0;
    for (; i > 0; i -= i & -i) ret += t[i];
    return ret;
  }
  inline int get(int l, int r) {
    if (!l--) return get(r);
    return get(r) - get(l);
  }
};
long long get_simple_number(const vector<int> &a) {
  set<int> was;
  int n = a.size();
  long long ret = 0;
  for (int i = 0; i < n; ++i) {
    for (int j = 1; j < a[i]; ++j) {
      if (!was.count(j)) ret = (ret + fact[n - i - 1]) % M;
    }
    was.insert(a[i]);
  }
  return ret;
}
long long get_dp(int n, int k) {
  if (lazy[n][k] != -1) return lazy[n][k];
  int &ret = lazy[n][k];
  ret = 0;
  if (n == 0 || k == n)
    ret = get_valid(n, k);
  else
    ret = (get_dp(n - 1, k) + get_dp(n, k + 1)) % M;
  return ret;
}
long long get_number(const vector<int> &p, const vector<int> &a) {
  Fenwik pa, aonly;
  int n = a.size();
  for (int i = 0; i < int(n); ++i) pa.upd(i + 1, 1);
  for (int i = 0; i < int(n); ++i) aonly.upd(i + 1, 1);
  long long ret = 0;
  for (int i = 0; i < n; ++i) {
    if (pa.get(p[i], p[i])) pa.upd(p[i], -1);
    int k = pa.get(n);
    int cnt_will = pa.get(a[i] - 1);
    int cnt_wont =
        aonly.get(a[i] - 1) - cnt_will - aonly.get(p[i], p[i]) * (p[i] < a[i]);
    int all_can = pa.get(n);
    long long passed = (get_dp(n - i - 1, all_can) * cnt_wont +
                        get_dp(n - i - 1, all_can - 1) * cnt_will) %
                       M;
    ret = (ret + passed) % M;
    aonly.upd(a[i], -1);
    if (pa.get(a[i], a[i])) pa.upd(a[i], -1);
  }
  return ret;
}
void test_mode() {
  vector<int> p = {1, 2, 3, 4};
  vector<int> a = {2, 1, 4, 3};
  cout << ("get_number(p, a)") << " = " << (get_number(p, a)) << endl;
  ;
  exit(0);
}
void smain() {
  init();
  int n;
  cin >> n;
  vector<int> prev;
  long long ans = 0;
  long long transitions = get_valid(n);
  for (int iter = 0; iter < int(n); ++iter) {
    vector<int> a(n);
    for (int i = 0; i < int(n); ++i) cin >> a[i];
    if (iter == 0) {
      long long cur = get_simple_number(a);
      ans = (ans + cur * pw(transitions, n - iter - 1)) % M;
    } else {
      long long cur = get_number(prev, a);
      ans = (ans + cur * pw(transitions, n - iter - 1)) % M;
    }
    prev = a;
  }
  cout << ans;
}
