#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
const int MOD = 998244353;
const int MAXN = 2000;
const int MAXS = 4 * MAXN;
int n;
int a[MAXN][MAXN];
pair<int, int> sval[MAXS];
void sinit(int x, int l, int r) {
  if (l == r) {
    sval[x] = make_pair(1, 0);
  } else {
    int m = l + (r - l) / 2;
    sinit(2 * x + 1, l, m);
    sinit(2 * x + 2, m + 1, r);
    sval[x] = make_pair(sval[2 * x + 1].first + sval[2 * x + 2].first,
                        sval[2 * x + 1].second + sval[2 * x + 2].second);
  }
}
void skill(int x, int l, int r, int IDX) {
  if (l == r) {
    sval[x] = make_pair(0, 0);
  } else {
    int m = l + (r - l) / 2;
    if (IDX <= m)
      skill(2 * x + 1, l, m, IDX);
    else
      skill(2 * x + 2, m + 1, r, IDX);
    sval[x] = make_pair(sval[2 * x + 1].first + sval[2 * x + 2].first,
                        sval[2 * x + 1].second + sval[2 * x + 2].second);
  }
}
void smark(int x, int l, int r, int IDX) {
  if (l == r) {
    sval[x] = make_pair(sval[x].second, sval[x].first);
  } else {
    int m = l + (r - l) / 2;
    if (IDX <= m)
      smark(2 * x + 1, l, m, IDX);
    else
      smark(2 * x + 2, m + 1, r, IDX);
    sval[x] = make_pair(sval[2 * x + 1].first + sval[2 * x + 2].first,
                        sval[2 * x + 1].second + sval[2 * x + 2].second);
  }
}
pair<int, int> sget(int x, int l, int r, int L, int R) {
  if (L <= l && r <= R) {
    return sval[x];
  } else {
    int m = l + (r - l) / 2;
    pair<int, int> ret = make_pair(0, 0);
    if (L <= m) {
      pair<int, int> cur = sget(2 * x + 1, l, m, L, R);
      ret = make_pair(ret.first + cur.first, ret.second + cur.second);
    }
    if (m + 1 <= R) {
      pair<int, int> cur = sget(2 * x + 2, m + 1, r, L, R);
      ret = make_pair(ret.first + cur.first, ret.second + cur.second);
    }
    return ret;
  }
}
int dp[MAXN + 1][MAXN + 1];
bool seenincur[MAXN], seeninprev[MAXN];
int calcsmaller(int* cur) {
  int ret = 0;
  sinit(0, 0, n - 1);
  for (int i = (0); i < (n); ++i) {
    skill(0, 0, n - 1, cur[i]);
    pair<int, int> cnt = sget(0, 0, n - 1, 0, cur[i]);
    ret = (ret + (long long)cnt.first * dp[n - i - 1][0]) % MOD;
  }
  return ret;
}
int calcsmaller(int* cur, int* prev) {
  int ret = 0;
  for (int i = (0); i < (n); ++i) seenincur[i] = seeninprev[i] = false;
  int numforbidden = n;
  sinit(0, 0, n - 1);
  for (int i = (0); i < (n); ++i) {
    skill(0, 0, n - 1, cur[i]);
    smark(0, 0, n - 1, prev[i]);
    pair<int, int> cnt = sget(0, 0, n - 1, 0, cur[i]);
    if (!seenincur[prev[i]] && prev[i] <= cur[i]) --cnt.second;
    ret =
        (ret +
         (long long)cnt.first *
             dp[n - i - 1][numforbidden - 1 - (!seenincur[prev[i]] ? 1 : 0)]) %
        MOD;
    ret = (ret +
           (long long)cnt.second *
               dp[n - i - 1][numforbidden - (!seenincur[prev[i]] ? 1 : 0)]) %
          MOD;
    if (!seenincur[prev[i]]) --numforbidden;
    if (!seeninprev[cur[i]]) --numforbidden;
    seenincur[cur[i]] = true;
    seeninprev[prev[i]] = true;
  }
  return ret;
}
void init() {
  for (int i = (0); i <= (n); ++i)
    for (int j = (0); j <= (i); ++j) {
      if (j >= 1) {
        dp[i][j] = ((long long)(i - j) * dp[i - 1][j - 1] +
                    (j >= 2 ? (long long)(j - 1) * dp[i - 1][j - 2] : 0)) %
                   MOD;
      } else if (i >= 1) {
        dp[i][j] = (long long)i * dp[i - 1][j] % MOD;
      } else {
        dp[i][j] = 1;
      }
    }
}
int solve() {
  init();
  int prod = 1, ret = 0;
  for (int i = n - 1; i >= 0; --i) {
    int cnt = i == 0 ? calcsmaller(a[i]) : calcsmaller(a[i], a[i - 1]);
    ret = (ret + (long long)prod * cnt) % MOD;
    prod = (long long)prod * dp[n][n] % MOD;
  }
  return ret;
}
void run() {
  scanf("%d", &n);
  for (int i = (0); i < (n); ++i)
    for (int j = (0); j < (n); ++j) scanf("%d", &a[i][j]), --a[i][j];
  printf("%d\n", solve());
}
int bfcalcsmaller(int* cur, int* prev) {
  vector<int> next(n);
  for (int i = (0); i < (n); ++i) next[i] = i;
  int ret = 0;
  do {
    bool smaller = false;
    for (int i = (0); i < (n); ++i)
      if (next[i] != cur[i]) {
        if (next[i] < cur[i]) smaller = true;
        break;
      }
    if (!smaller) continue;
    if (prev != NULL) {
      bool ok = true;
      for (int i = (0); i < (n); ++i)
        if (next[i] == prev[i]) {
          ok = false;
          break;
        }
      if (!ok) continue;
    }
    ++ret;
  } while (next_permutation(next.begin(), next.end()));
  return ret;
}
void stress1() {
  n = 10;
  init();
  for (int rep = (0); rep < (1000); ++rep) {
    vector<int> a(n), b(n);
    for (int i = (0); i < (n); ++i) a[i] = b[i] = i;
    while (true) {
      random_shuffle(a.begin(), a.end());
      random_shuffle(b.begin(), b.end());
      bool ok = true;
      for (int i = (0); i < (n); ++i)
        if (a[i] == b[i]) ok = false;
      if (ok) break;
    }
    bool useprev = false;
    int have =
        useprev ? calcsmaller(a.data(), b.data()) : calcsmaller(a.data());
    int want = bfcalcsmaller(a.data(), useprev ? b.data() : NULL);
    if (have == want) {
      printf(".");
      continue;
    }
    printf("err have=%d want=%d\n", have, want);
  }
}
int main() {
  run();
  return 0;
}
