#include <bits/stdc++.h>
using namespace std;
const int INF = 2e9;
const long long LINF = 2e16;
const int magic = 348;
const int MOD = 998244353;
const double eps = 1e-10;
const double pi = acos(-1);
struct fastio {
  static const int S = 1e7;
  char rbuf[S + 48], wbuf[S + 48];
  int rpos, wpos, len;
  fastio() { rpos = len = wpos = 0; }
  inline char Getchar() {
    if (rpos == len) rpos = 0, len = fread(rbuf, 1, S, stdin);
    if (!len) return EOF;
    return rbuf[rpos++];
  }
  template <class T>
  inline void Get(T &first) {
    char ch;
    bool f;
    T res;
    while (!isdigit(ch = Getchar()) && ch != '-') {
    }
    if (ch == '-')
      f = false, res = 0;
    else
      f = true, res = ch - '0';
    while (isdigit(ch = Getchar())) res = res * 10 + ch - '0';
    first = (f ? res : -res);
  }
  inline void getstring(char *s) {
    char ch;
    while ((ch = Getchar()) <= 32) {
    }
    for (; ch > 32; ch = Getchar()) *s++ = ch;
    *s = '\0';
  }
  inline void flush() {
    fwrite(wbuf, 1, wpos, stdout);
    fflush(stdout);
    wpos = 0;
  }
  inline void Writechar(char ch) {
    if (wpos == S) flush();
    wbuf[wpos++] = ch;
  }
  template <class T>
  inline void Print(T first, char ch) {
    char s[20];
    int pt = 0;
    if (first == 0)
      s[++pt] = '0';
    else {
      if (first < 0) Writechar('-'), first = -first;
      while (first) s[++pt] = '0' + first % 10, first /= 10;
    }
    while (pt) Writechar(s[pt--]);
    Writechar(ch);
  }
  inline void printstring(char *s) {
    int pt = 1;
    while (s[pt] != '\0') Writechar(s[pt++]);
  }
} io;
template <typename T>
inline void check_max(T &first, T cmp) {
  first = max(first, cmp);
}
template <typename T>
inline void check_min(T &first, T cmp) {
  first = min(first, cmp);
}
template <typename T>
inline T myabs(T first) {
  return first >= 0 ? first : -first;
}
template <typename T>
inline T gcd(T first, T second) {
  return second == 0 ? first : gcd(second, first % second);
}
inline int add(int first) {
  if (first >= MOD) first -= MOD;
  return first;
}
inline int add(int first, int MO) {
  if (first >= MO) first -= MO;
  return first;
}
inline int sub(int first) {
  if (first < 0) first += MOD;
  return first;
}
inline int sub(int first, int MO) {
  if (first < 0) first += MO;
  return first;
}
inline void Add(int &first, int second) { first = add(first + second); }
inline void Add(int &first, int second, int MO) {
  first = add(first + second, MO);
}
inline void Sub(int &first, int second) { first = sub(first - second); }
inline void Sub(int &first, int second, int MO) {
  first = sub(first - second, MO);
}
template <typename T>
inline int quick_pow(int first, T second) {
  int res = 1;
  while (second) {
    if (second & 1) res = 1ll * res * first % MOD;
    first = 1ll * first * first % MOD;
    second >>= 1;
  }
  return res;
}
template <typename T>
inline int quick_pow(int first, T second, int MO) {
  int res = 1;
  while (second) {
    if (second & 1) res = 1ll * res * first % MO;
    first = 1ll * first * first % MO;
    second >>= 1;
  }
  return res;
}
const int MAXN = 2000;
int n, a[MAXN + 48][MAXN + 48];
int fac[MAXN + 48];
int d[MAXN + 48][MAXN + 48], pw[MAXN + 48];
inline void init() {
  d[0][0] = 1;
  d[1][0] = 1;
  for (register int i = 2; i <= n; i++)
    for (register int j = 0; j <= i; j++)
      if (i != j)
        d[i][j] = add(1ll * (i - j) * d[i - 1][j] % MOD +
                      1ll * j * d[i - 1][j - 1] % MOD);
      else
        d[i][j] = 1ll * (i - 1) * d[i - 1][j - 2] % MOD;
  fac[0] = 1;
  for (register int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
  pw[0] = 1;
  for (register int i = 1; i <= n; i++) pw[i] = 1ll * pw[i - 1] * d[n][n] % MOD;
}
int cnt[MAXN + 48];
struct BIT {
  int c[MAXN + 48];
  inline void init() { memset(c, 0, sizeof(c)); }
  inline void modify(int first, int delta) {
    while (first <= n) c[first] += delta, first += first & (-first);
  }
  inline int query(int first) {
    int res = 0;
    while (first) res += c[first], first ^= first & (-first);
    return res;
  }
  inline int calc(int l, int r) { return query(r) - query(l - 1); }
} s1, s2;
struct SuperBIT {
  int c[MAXN + 48], cc[MAXN + 48];
  inline void init() {
    memset(c, 0, sizeof(c));
    memset(cc, 0, sizeof(cc));
  }
  inline void modify(int first, int delta) {
    cc[first] += delta;
    if ((delta == 1 && cc[first] == 1) || (delta == -1 && cc[first] == 0))
      while (first <= n) c[first] += delta, first += first & (-first);
  }
  inline int query(int first) {
    int res = 0;
    while (first) res += c[first], first ^= first & (-first);
    return res;
  }
  inline int calc(int l, int r) { return query(r) - query(l - 1); }
} s3;
int main() {
  scanf("%d", &n);
  for (register int i = 1; i <= n; i++)
    for (register int j = 1; j <= n; j++) scanf("%d", &a[i][j]);
  init();
  s1.init();
  int ans = 0;
  for (register int i = 1; i <= n; i++) {
    int avai = a[1][i] - 1 - s1.query(a[1][i] - 1);
    Add(ans, 1ll * avai * fac[n - i] % MOD * pw[n - 1] % MOD);
    s1.modify(a[1][i], 1);
  }
  for (register int i = 2; i <= n; i++) {
    s1.init();
    s2.init();
    s3.init();
    memset(cnt, 0, sizeof(cnt));
    int Cnt = 0;
    for (register int j = 2; j <= n; j++)
      s2.modify(a[i - 1][j], 1), s3.modify(a[i - 1][j], 1), cnt[a[i - 1][j]]++;
    for (register int j = 1; j <= n; j++) {
      int avai = a[i][j] - 1 - s1.query(a[i][j] - 1) -
                 (a[i - 1][j] < a[i][j] && !s1.calc(a[i - 1][j], a[i - 1][j]));
      int m = (n - j) - Cnt;
      int type1 = a[i][j] - 1 - s3.query(a[i][j] - 1) -
                  (a[i - 1][j] < a[i][j] && !s3.calc(a[i - 1][j], a[i - 1][j]));
      int type2 = avai - type1;
      Add(ans, 1ll * type1 * d[n - j][m] % MOD * pw[n - i] % MOD);
      if (m) Add(ans, 1ll * type2 * d[n - j][m - 1] % MOD * pw[n - i] % MOD);
      if (j != n) {
        cnt[a[i][j]]++;
        if (cnt[a[i][j]] == 2) Cnt++;
        cnt[a[i - 1][j + 1]]--;
        if (cnt[a[i - 1][j + 1]] == 1) Cnt--;
        s1.modify(a[i][j], 1);
        s3.modify(a[i][j], 1);
        s2.modify(a[i - 1][j + 1], -1);
        s3.modify(a[i - 1][j + 1], -1);
      }
    }
  }
  printf("%d\n", ans);
  io.flush();
  return 0;
}

### Prompt

Please provide a cpp coded solution to the problem described below:

Petya collects beautiful matrix.

A matrix of size n × n is beautiful if: 

  * All elements of the matrix are integers between 1 and n; 
  * For every row of the matrix, all elements of this row are different; 
  * For every pair of vertically adjacent elements, these elements are different. 



Today Petya bought a beautiful matrix a of size n × n, and now he wants to determine its rarity.

The rarity of the matrix is its index in the list of beautiful matrices of size n × n, sorted in lexicographical order. Matrix comparison is done row by row. (The index of lexicographically smallest matrix is zero).

Since the number of beautiful matrices may be huge, Petya wants you to calculate the rarity of the matrix a modulo 998 244 353.

Input

The first line contains one integer n (1 ≤ n ≤ 2000) — the number of rows and columns in a.

Each of the next n lines contains n integers a_{i,j} (1 ≤ a_{i,j} ≤ n) — the elements of a.

It is guaranteed that a is a beautiful matrix.

Output

Print one integer — the rarity of matrix a, taken modulo 998 244 353.

Examples

Input


2
2 1
1 2


Output


1


Input


3
1 2 3
2 3 1
3 1 2


Output


1


Input


3
1 2 3
3 1 2
2 3 1


Output


3

Note

There are only 2 beautiful matrices of size 2 × 2:

<image>

There are the first 5 beautiful matrices of size 3 × 3 in lexicographical order:

<image>

### Response

```cpp
#include <bits/stdc++.h>
using namespace std;
const int INF = 2e9;
const long long LINF = 2e16;
const int magic = 348;
const int MOD = 998244353;
const double eps = 1e-10;
const double pi = acos(-1);
struct fastio {
  static const int S = 1e7;
  char rbuf[S + 48], wbuf[S + 48];
  int rpos, wpos, len;
  fastio() { rpos = len = wpos = 0; }
  inline char Getchar() {
    if (rpos == len) rpos = 0, len = fread(rbuf, 1, S, stdin);
    if (!len) return EOF;
    return rbuf[rpos++];
  }
  template <class T>
  inline void Get(T &first) {
    char ch;
    bool f;
    T res;
    while (!isdigit(ch = Getchar()) && ch != '-') {
    }
    if (ch == '-')
      f = false, res = 0;
    else
      f = true, res = ch - '0';
    while (isdigit(ch = Getchar())) res = res * 10 + ch - '0';
    first = (f ? res : -res);
  }
  inline void getstring(char *s) {
    char ch;
    while ((ch = Getchar()) <= 32) {
    }
    for (; ch > 32; ch = Getchar()) *s++ = ch;
    *s = '\0';
  }
  inline void flush() {
    fwrite(wbuf, 1, wpos, stdout);
    fflush(stdout);
    wpos = 0;
  }
  inline void Writechar(char ch) {
    if (wpos == S) flush();
    wbuf[wpos++] = ch;
  }
  template <class T>
  inline void Print(T first, char ch) {
    char s[20];
    int pt = 0;
    if (first == 0)
      s[++pt] = '0';
    else {
      if (first < 0) Writechar('-'), first = -first;
      while (first) s[++pt] = '0' + first % 10, first /= 10;
    }
    while (pt) Writechar(s[pt--]);
    Writechar(ch);
  }
  inline void printstring(char *s) {
    int pt = 1;
    while (s[pt] != '\0') Writechar(s[pt++]);
  }
} io;
template <typename T>
inline void check_max(T &first, T cmp) {
  first = max(first, cmp);
}
template <typename T>
inline void check_min(T &first, T cmp) {
  first = min(first, cmp);
}
template <typename T>
inline T myabs(T first) {
  return first >= 0 ? first : -first;
}
template <typename T>
inline T gcd(T first, T second) {
  return second == 0 ? first : gcd(second, first % second);
}
inline int add(int first) {
  if (first >= MOD) first -= MOD;
  return first;
}
inline int add(int first, int MO) {
  if (first >= MO) first -= MO;
  return first;
}
inline int sub(int first) {
  if (first < 0) first += MOD;
  return first;
}
inline int sub(int first, int MO) {
  if (first < 0) first += MO;
  return first;
}
inline void Add(int &first, int second) { first = add(first + second); }
inline void Add(int &first, int second, int MO) {
  first = add(first + second, MO);
}
inline void Sub(int &first, int second) { first = sub(first - second); }
inline void Sub(int &first, int second, int MO) {
  first = sub(first - second, MO);
}
template <typename T>
inline int quick_pow(int first, T second) {
  int res = 1;
  while (second) {
    if (second & 1) res = 1ll * res * first % MOD;
    first = 1ll * first * first % MOD;
    second >>= 1;
  }
  return res;
}
template <typename T>
inline int quick_pow(int first, T second, int MO) {
  int res = 1;
  while (second) {
    if (second & 1) res = 1ll * res * first % MO;
    first = 1ll * first * first % MO;
    second >>= 1;
  }
  return res;
}
const int MAXN = 2000;
int n, a[MAXN + 48][MAXN + 48];
int fac[MAXN + 48];
int d[MAXN + 48][MAXN + 48], pw[MAXN + 48];
inline void init() {
  d[0][0] = 1;
  d[1][0] = 1;
  for (register int i = 2; i <= n; i++)
    for (register int j = 0; j <= i; j++)
      if (i != j)
        d[i][j] = add(1ll * (i - j) * d[i - 1][j] % MOD +
                      1ll * j * d[i - 1][j - 1] % MOD);
      else
        d[i][j] = 1ll * (i - 1) * d[i - 1][j - 2] % MOD;
  fac[0] = 1;
  for (register int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
  pw[0] = 1;
  for (register int i = 1; i <= n; i++) pw[i] = 1ll * pw[i - 1] * d[n][n] % MOD;
}
int cnt[MAXN + 48];
struct BIT {
  int c[MAXN + 48];
  inline void init() { memset(c, 0, sizeof(c)); }
  inline void modify(int first, int delta) {
    while (first <= n) c[first] += delta, first += first & (-first);
  }
  inline int query(int first) {
    int res = 0;
    while (first) res += c[first], first ^= first & (-first);
    return res;
  }
  inline int calc(int l, int r) { return query(r) - query(l - 1); }
} s1, s2;
struct SuperBIT {
  int c[MAXN + 48], cc[MAXN + 48];
  inline void init() {
    memset(c, 0, sizeof(c));
    memset(cc, 0, sizeof(cc));
  }
  inline void modify(int first, int delta) {
    cc[first] += delta;
    if ((delta == 1 && cc[first] == 1) || (delta == -1 && cc[first] == 0))
      while (first <= n) c[first] += delta, first += first & (-first);
  }
  inline int query(int first) {
    int res = 0;
    while (first) res += c[first], first ^= first & (-first);
    return res;
  }
  inline int calc(int l, int r) { return query(r) - query(l - 1); }
} s3;
int main() {
  scanf("%d", &n);
  for (register int i = 1; i <= n; i++)
    for (register int j = 1; j <= n; j++) scanf("%d", &a[i][j]);
  init();
  s1.init();
  int ans = 0;
  for (register int i = 1; i <= n; i++) {
    int avai = a[1][i] - 1 - s1.query(a[1][i] - 1);
    Add(ans, 1ll * avai * fac[n - i] % MOD * pw[n - 1] % MOD);
    s1.modify(a[1][i], 1);
  }
  for (register int i = 2; i <= n; i++) {
    s1.init();
    s2.init();
    s3.init();
    memset(cnt, 0, sizeof(cnt));
    int Cnt = 0;
    for (register int j = 2; j <= n; j++)
      s2.modify(a[i - 1][j], 1), s3.modify(a[i - 1][j], 1), cnt[a[i - 1][j]]++;
    for (register int j = 1; j <= n; j++) {
      int avai = a[i][j] - 1 - s1.query(a[i][j] - 1) -
                 (a[i - 1][j] < a[i][j] && !s1.calc(a[i - 1][j], a[i - 1][j]));
      int m = (n - j) - Cnt;
      int type1 = a[i][j] - 1 - s3.query(a[i][j] - 1) -
                  (a[i - 1][j] < a[i][j] && !s3.calc(a[i - 1][j], a[i - 1][j]));
      int type2 = avai - type1;
      Add(ans, 1ll * type1 * d[n - j][m] % MOD * pw[n - i] % MOD);
      if (m) Add(ans, 1ll * type2 * d[n - j][m - 1] % MOD * pw[n - i] % MOD);
      if (j != n) {
        cnt[a[i][j]]++;
        if (cnt[a[i][j]] == 2) Cnt++;
        cnt[a[i - 1][j + 1]]--;
        if (cnt[a[i - 1][j + 1]] == 1) Cnt--;
        s1.modify(a[i][j], 1);
        s3.modify(a[i][j], 1);
        s2.modify(a[i - 1][j + 1], -1);
        s3.modify(a[i - 1][j + 1], -1);
      }
    }
  }
  printf("%d\n", ans);
  io.flush();
  return 0;
}

```