#include <bits/stdc++.h>
using namespace std;
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char *s) { return to_string((string)s); }
string to_string(bool b) { return (b ? "true" : "false"); }
template <typename A, typename B>
string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <typename A>
string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) {
      res += ", ";
    }
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
const int md = 998244353;
inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}
inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}
inline int mul(int x, int y) { return (long long)x * y % md; }
inline int power(int x, int y) {
  int result = 1;
  for (; y; y >>= 1, x = mul(x, x)) {
    if (y & 1) {
      result = mul(result, x);
    }
  }
  return result;
}
template <typename T>
class fenwick_t {
 public:
  vector<T> fenw;
  int n;
  fenwick_t(int n) : n(n) { fenw.resize(n); }
  void modify(int x, T value) {
    while (x < n) {
      fenw[x] += value;
      x |= x + 1;
    }
  }
  T query(int x) {
    T result{};
    while (x >= 0) {
      result += fenw[x];
      x = (x & x + 1) - 1;
    }
    return result;
  }
  T get(int l, int r) { return query(r) - query(l - 1); }
};
int main() {
  int n;
  scanf("%d", &n);
  if (n == 1) {
    puts("0");
    return 0;
  }
  vector<int> w(n + 1);
  w[1] = 0;
  w[2] = 1;
  for (int i = 3; i <= n; ++i) {
    w[i] = mul(i - 1, w[i - 1] + w[i - 2]);
  }
  vector<int> fact(n + 1);
  fact[0] = 1;
  for (int i = 1; i <= n; ++i) {
    fact[i] = mul(fact[i - 1], i);
  }
  vector<vector<int>> f(n + 1, vector<int>(n + 1));
  for (int i = 0; i <= n; ++i) {
    f[i][0] = fact[i];
    for (int j = 1; j <= i; ++j) {
      f[i][j] = f[i][j - 1];
      sub(f[i][j], f[i - 1][j - 1]);
    }
  }
  vector<vector<int>> a(n, vector<int>(n));
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      scanf("%d", &a[i][j]);
      --a[i][j];
    }
  }
  int answer = 0;
  {
    fenwick_t<int> fenw(n);
    for (int i = 0; i < n; ++i) {
      fenw.modify(i, 1);
    }
    int coef = power(w[n], n - 1);
    for (int i = 0; i < n; ++i) {
      fenw.modify(a[0][i], -1);
      add(answer, mul(fact[n - i - 1], mul(coef, fenw.query(a[0][i] - 1))));
    }
  }
  for (int i = 1; i < n; ++i) {
    fenwick_t<int> foo(n), bar(n);
    vector<int> cnt(n);
    int current = 0;
    auto insert = [&](int x) {
      if (++cnt[x] == 2) {
        ++current;
        foo.modify(x, 1);
      }
    };
    auto get = [&](int x, int y) { return y < 0 || y > x ? 0 : f[x][y]; };
    int coef = power(w[n], n - i - 1);
    for (int j = n - 1; ~j; --j) {
      insert(a[i - 1][j]);
      insert(a[i][j]);
      bar.modify(a[i][j], 1);
      int u = foo.query(a[i][j] - 1), v = bar.query(a[i][j] - 1) - u;
      add(answer,
          mul(coef,
              mul(u, get(n - j - 1, current - (cnt[a[i - 1][j]] == 2) - 1))));
      add(answer,
          mul(coef, mul(v, get(n - j - 1, current - (cnt[a[i - 1][j]] == 2)))));
      if (cnt[a[i - 1][j]] == 2 && a[i - 1][j] < a[i][j]) {
        sub(answer, mul(coef, get(n - j - 1, current - 2)));
      }
    }
  }
  printf("%d\n", answer);
  return 0;
}
