#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
#define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { x = (unsigned long long)x * that.inv().x % MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    int a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (p[i] == -1) continue;
      a0 += bit.query(p[i], n);
      bit.add(p[i], 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
#define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { (x *= that.inv().x) %= MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    int a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (!used[i]) continue;
      a0 += bit.query(i, n);
      bit.add(i, 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      dump(i);
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
#define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { (x *= that.inv().x) %= MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    int a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (!used[i]) continue;
      a0 += bit.query(0, i);
      bit.add(i, 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      dump(i);
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
// #define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { x = (unsigned long long)x * that.inv().x % MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    int a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (p[i] == -1) continue;
      a0 += bit.query(p[i], n);
      bit.add(p[i], 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
#define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { (x *= that.inv().x) %= MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    int a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (p[i] == -1) continue;
      a0 += bit.query(p[i], n);
      bit.add(p[i], 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0, max_i = (n); i < max_i; i++)
#define REPI(i, a, b) for (int i = (a), max_i = (b); i < max_i; i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define fi first
#define se second
// #define int long long
using namespace std;
using ll = long long;
using II = pair<int, int>; using VII = vector<II>; using VVII = vector<VII>;
using VI = vector<int>; using VVI = vector<VI>; using VVVI = vector<VVI>;
template <class T = int> inline bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <class T = int> inline bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
template <class T> ostream& operator<<(ostream &s, const vector<T>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : " "); return s; }
template <class T> ostream& operator<<(ostream &s, const vector<vector<T>>& d) { REP (i, d.size()) s << d[i] << (i == d.size() - 1 ? "" : "\n"); return s; }
template <class T, class S> ostream& operator<<(ostream &s, const pair<T, S>& p) { s << "{" << p.first << ", " << p.second << "}"; return s; }
template <class T, class S> ostream& operator<<(ostream& s, const map<T, S> m) { for (auto it = m.begin(); it != m.end(); it++) { s << *it << (next(it) == m.end() ? "" : "\n"); } return s; }
#ifdef _MY_DEBUG
  #define dump(...) cerr << "/* " << #__VA_ARGS__ << " :[" << __LINE__ << ":" << __FUNCTION__ << "]" << endl, dump_func(__VA_ARGS__), cerr << "*/\n\n";
#else
  #define dump(...)
#endif
void dump_func() { cerr << endl; }
template <class Head, class... Tail> void dump_func(Head&& h, Tail&&... t) { cerr << h << (sizeof...(Tail) == 0 ? "" : ", "), dump_func(forward<Tail>(t)...); }
struct Fast { Fast() { cin.tie(0); ios::sync_with_stdio(false); } } fast;
constexpr int MOD = 998244353;
template <int MD>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int x_) { if ((x = x_ % MD + MD) >= MD) x -= MD; }

  ModInt& operator+=(ModInt that) { if ((x += that.x) >= MD) x -= MD; return *this; }
  ModInt& operator*=(ModInt that) { x = (unsigned long long)x * that.x % MD; return *this; }
  ModInt& operator-=(ModInt that) { if ((x -= that.x) <= MD) x += MD; return *this; }
  ModInt& operator/=(ModInt that) { x = (unsigned long long)x * that.inv().x % MD; return *this; }

  ModInt operator-() const { return -x < 0 ? MD - x : -x; }
  ModInt operator+(ModInt that) const { return ModInt(*this) += that; }
  ModInt operator*(ModInt that) const { return ModInt(*this) *= that; }
  ModInt operator-(ModInt that) const { return ModInt(*this) -= that; }
  ModInt operator/(ModInt that) const { return ModInt(*this) /= that; }
  ModInt pow(int n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return (*this).pow(MD - 2); }
  friend ostream& operator<<(ostream& s, ModInt<MD> a) { s << a.x; return s; }
};
using mint = ModInt<MOD>;

// 0-indexed
class BinaryIndexedTree {
  int max_pow; // N以下の最大の2べき
  void init() {
    for (max_pow = 1; max_pow <= N / 2; max_pow *= 2);
    REP (i, N - 1) if ((i | (i + 1)) < N) {
      bit[i | (i + 1)] += bit[i];
    }
  }
public:
  VI bit; int N;
  BinaryIndexedTree(int n, int x = 0) : N(n), bit(n, x) { init(); }
  BinaryIndexedTree(const VI& a) : N(a.size()), bit(a) { init(); }
  // k番目にxを加算
  void add(int k, int x) {
    for (int i = k; i < N; i |= i + 1) { bit[i] += x; }
  }

  // [0, k)、k == 0のときは0を返す
  int sum(int k) {
    int ret = 0;
    for (int i = k - 1; i >= 0; i = (i & (i + 1)) - 1) {
      ret += bit[i];
    }
    return ret;
  }
  int sum() { return sum(N); }

  // [a, b)
  int query(int a, int b) {
    assert(a <= b);
    return sum(b) - sum(a);
  }
  int operator[](int k) {
    return query(k, k + 1);
  }

  // k番目をxに
  void update(int k, int x) {
    add(k, x - operator[](k));
  }

  // 注: 中身が全て正のときしか動かない
  // sum(i + 1) >= xとなるような最小のi
  int lower_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] < x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) >= xとなるような最小のi
  int lower_bound(int begin, int x) {
    int lb = lower_bound(x + sum(begin));
    return max(begin, lb);
  }
  // sum(i + 1) > xとなるような最小のi
  int upper_bound(int x) {
    int i = -1;
    for (int w = max_pow; w > 0; w /= 2) {
      if (i + w < N && bit[i + w] <= x) {
        x -= bit[i + w];
        i += w;
      }
    }
    return i + 1;
  }
  // query[begin, i + 1) > xとなるような最小のi
  int upper_bound(int begin, int x) {
    int ub = upper_bound(x + sum(begin));
    return max(begin, ub);
  }
};

signed main() {
  int n; cin >> n;
  VI p(n);
  vector<bool> used(n);
  int m = 0;
  REP (i, n) {
    cin >> p[i];
    if (p[i] != -1) {
      p[i]--;
      used[p[i]] = true;
    } else {
      m++;
    }
  }
  dump(m);
  mint ans = 0;
  // 0
  {
    mint a0 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (p[i] == -1) continue;
      a0 += bit.query(p[i], n);
      bit.add(p[i], 1);
    }
    dump(a0);
    ans += a0;
  }

  // 1, 2
  {
    mint a1 = 0;
    BinaryIndexedTree bit(n);
    REP (i, n) {
      if (used[i]) continue;
      bit.add(i, 1);
    }
    int l = 0;
    REP (i, n) {
      if (p[i] == -1) {
        l++;
      } else {
        // 1
        int s = bit.query(0, p[i]);
        a1 += mint(m - l) * mint(s) / mint(m);
        // 2
        int b = bit.query(p[i], n);
        a1 += mint(l) * mint(b) / mint(m);
        dump(i, l, s, b);
        assert(s + b == m);
      }
    }
    dump(a1);
    ans += a1;
  }

  // 3
  mint a3 = mint(m) * mint(m - 1) / mint(4);
  dump(a3);

  ans += a3;

  cout << ans << endl;
}


#include<bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define EB emplace_back
#define MP make_pair
#define all(o) (o).begin(), (o).end()
#define mset(m,v) memset(m,v,sizeof(m))
#define fr(i,n) for(lli i=0;i<n;++i)
#define rep(i,a,b) for(lli i=a;i<=b;++i)
#define remin(a,b) (a=min((a),(b)))
#define remax(a,b) (a=max((a),(b)))
#define endl '\n'
typedef long long lli;        typedef long double ld;
typedef pair<lli,lli> ii;     typedef vector<lli> vi;
typedef vector<ii> vii;       typedef vector<vi> graph;
long long MOD=998244353;     long double EPS=1e-9;
#define debarr(a,n) cerr<<#a<<" : ";for(lli i=0;i<n;i++) cerr<<a[i]<<" "; cerr<<endl;
#define debmat(mat,row,col) cerr<<#mat<<" :\n";for(lli i=0;i<row;i++) {for(lli j=0;j<col;j++) cerr<<mat[i][j]<<" ";cerr<<endl;}
#define pr(...) dbs(#__VA_ARGS__, __VA_ARGS__)
template <class S, class T>ostream& operator <<(ostream& os, const pair<S, T>& p) {return os << "(" << p.first << ", " << p.second << ")";}template <class T>ostream& operator <<(ostream& os, const vector<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T>ostream& operator <<(ostream& os, const unordered_set<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class S, class T>ostream& operator <<(ostream& os, const unordered_map<S, T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T>ostream& operator <<(ostream& os, const set<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class T>ostream& operator <<(ostream& os, const multiset<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class S, class T>ostream& operator <<(ostream& os, const map<S, T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class T> void dbs(string str, T t) {cerr << str << " : " << t << "\n";}
template <class T, class... S> void dbs(string str, T t, S... s) {lli idx = str.find(','); cerr << str.substr(0, idx) << " : " << t << ","; dbs(str.substr(idx + 1), s...);}template <class T> void prc(T a, T b) {cerr << "["; for (T i = a; i != b; ++i) {if (i != a) cerr << ", "; cerr << *i;} cerr << "]\n";}
lli binpow(lli b,lli p,lli mod){lli ans=1;for(;p;p>>=1){if(p&1)ans=ans*b%mod;b=b*b%mod;}return ans;}

void pre(){

}

#define LSOne(i) (i&(-i))
struct Fen{
    vi ft;
    Fen(lli i = 0){
        ft.assign(i+1,0);
    }
    lli rsq(lli b){b++;
        lli sumer=0;
        for(;b>0;b-=LSOne(b))sumer+=ft[b];
        return  sumer;
    }
    void addat(lli k,lli v){k++;
        for(;k<(lli)ft.size();k+=LSOne(k))ft[k]+=v;
    }
};

lli merger(vi &arr,lli l,lli r){
    lli i=l;
    lli mid=(l+r)>>1;
    lli j=((l+r)>>1)+1;
    lli a[r-l+1];
    lli c=0;
    lli ans=0;
    while(i<=mid&&j<=r){
        if(arr[i]<=arr[j]){
            a[c++]=arr[i++];
        }
        else{
            ans+=mid+1-i;
            a[c++]=arr[j++];
        }
    }
    while(i<=mid){
        a[c++]=arr[i++];
    }
    while(j<=r){
        a[c++]=arr[j++];
    }
    c=0;
    for(int i=l;i<=r;i++){
        arr[i]=a[c++];
    }
    return ans;
}

lli mergesort(vi &arr,lli l,lli r){
    if(l==r){
        return 0;
    }
    int mid=(l+r)>>1;
    lli ans=0;
    ans+=mergesort(arr,l,mid);
    ans+=mergesort(arr,mid+1,r);
    ans+=merger(arr,l,r);
    return ans;
}

vi notseen;
lli arr[200200];

bool seen[200200];
vi getcomp;
void solve(){
    lli n;
    cin>>n;
    Fen ff(n+1);
    lli cnt=0;
    fr(i,n){
        cin>>arr[i];
        if(arr[i]!=-1){
            seen[arr[i]]=1;
            getcomp.EB(arr[i]);
        }
        else{
            ff.addat(i,1);
            cnt++;
        }
    }
    rep(i,1,n){
        if(!seen[i]){
            notseen.EB(i);
        }
    }
    lli ans=(cnt*(cnt-1)%MOD)*binpow(4,MOD-2,MOD)%MOD;
    if(cnt!=n){
        ans=(ans+mergesort(getcomp,0,(int)getcomp.size()-1))%MOD;
    }
    ll ppp = 0;
    if(cnt!=0){
        fr(i,n){
            if(arr[i]!=-1){
                lli pos=cnt-ppp;
                lli lessnums=lower_bound(all(notseen),arr[i])-notseen.begin();
                ans=(ans+(((lessnums*pos)%MOD)*binpow(cnt,MOD-2,MOD))%MOD)%MOD;
                lli pos2=ppp;
                lli morenums=cnt-lessnums;
                ans=(ans+(((morenums*pos2)%MOD)*binpow(cnt,MOD-2,MOD))%MOD)%MOD;
            }
            else
                ppp++;
        }
    }
    cout<<ans%MOD<<endl;
}

signed main(){
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);
    pre();lli t=1;//cin>>t;
    for(lli i=1;i<=t;i++){
        //cout<<"Case #"<<i<<": ";
        solve();
    }
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define pb push_back
#define mp make_pair
#define fi first
#define sec second
typedef long long  ll;
typedef long double  ld;
#define pii pair<ll,ll>
#define pic pair<ll,char>
#define vi vector< ll >
#define vvi vector< vi >
#define vpi vector< pii >
#define vvpi vector< vpi >
#define st  set <ll, greater <ll> >
#define mst  multiset <ll, greater <ll> >
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mapp  unordered_map <ll, ll>
#define ppii pair< pii, pii >
#define test(t) ll t;cin>>t;while(t--)
#define inarr(n) ll arr[n];for(ll i=0;i<n;i++)cin>>arr[i];
#define ingra(m) vvi arr(100005);for(ll i=0;i<m;i++){ll u,v;cin>>u>>v;arr[u].pb(v);arr[v].pb(u);}
#define mem(a,b) memset(a,b,sizeof(a))
#define inn freopen("input.txt", "r", stdin)
#define outt freopen("output.txt", "w", stdout)
#define all(arr) arr.begin(),arr.end()
ll power(ll x,ll y){ll res = 1;while(y){if(y&1) res = (res*x)%mod;y=y/2,x=(x*x)%mod;}return res%mod;}
vi temp;
ll getSum(ll BITree[], ll index)
{
    ll sum = 0; // Initialize result

    // Traverse ancestors of BITree[index]
    while (index > 0)
    {
        // Add current element of BITree to sum
        sum += BITree[index];

        // Move index to parent node in getSum View
        index -= index & (-index);
    }
    return sum;
}

// Updates a node in Binary Index Tree (BITree) at given index
// in BITree.  The given value 'val' is added to BITree[i] and
// all of its ancestors in tree.
void updateBIT(ll BITree[], ll n, ll index, ll val)
{
    // Traverse all ancestors and add 'val'
    while (index <= n)
    {
       // Add 'val' to current node of BI Tree
       BITree[index] += val;

       // Update index to that of parent in update View
       index += index & (-index);
    }
}

// Returns inversion count arr[0..n-1]
ll getInvCount(ll n)
{
    ll invcount = 0; // Initialize result

    // Find maximum element in arr[]
    ll maxElement = 0;
    for (ll i=0; i<n; i++)
        if (maxElement < temp[i])
            maxElement = temp[i];

    // Create a BIT with size equal to maxElement+1 (Extra
    // one is used so that elements can be directly be
    // used as index)
    ll BIT[maxElement+1];
    for (ll i=1; i<=maxElement; i++)
        BIT[i] = 0;

    // Traverse all elements from right.
    for (ll i=n-1; i>=0; i--)
    {
        // Get count of elements smaller than temp[i]
        invcount += getSum(BIT, temp[i]-1);

        // Add current element to BIT
        updateBIT(BIT, maxElement, temp[i], 1);
    }

    return invcount;
}
signed main()
{
    fast;
    ll n,i;
    set < ll > lol;
    cin>>n;
    ll ans = 0;
    ll arr[n+1];
    for(i=1;i<=n;i++){
        cin>>arr[i];
        if(arr[i]!=-1)
            lol.insert(arr[i]),temp.pb(arr[i]);
    }
    vi useless;
    for(i=1;i<=n;i++)
    {
        if(lol.find(i)==lol.end())
        {
            useless.pb(i);
        }
    }
    ans = (useless.size()*(useless.size()-1)%mod)*power(4,mod-2)%mod;
    ans+=getInvCount(temp.size());
    ans%=mod;
    ll cnt = 0;
    ll tot = useless.size();
    ll pp = power(tot,mod-2);
    for(i=1;i<=n;i++)
    {
        if(arr[i]!=-1)
        {
            ll in = lower_bound(all(useless),arr[i])-useless.begin();
            ans+=((tot-cnt)*in%mod*pp%mod);
            ans%=mod;
            ans+=((tot-in)*(cnt)%mod*pp%mod);
            ans%=mod;
        }
        else
            cnt++;
    }
    cout<<ans;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define pb push_back
#define mp make_pair
#define fi first
#define sec second
typedef long long  ll;
typedef long double  ld;
#define pii pair<ll,ll>
#define pic pair<ll,char>
#define vi vector< ll >
#define vvi vector< vi >
#define vpi vector< pii >
#define vvpi vector< vpi >
#define st  set <ll, greater <ll> >
#define mst  multiset <ll, greater <ll> >
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mapp  unordered_map <ll, ll>
#define ppii pair< pii, pii >
#define test(t) ll t;cin>>t;while(t--)
#define inarr(n) ll arr[n];for(ll i=0;i<n;i++)cin>>arr[i];
#define ingra(m) vvi arr(100005);for(ll i=0;i<m;i++){ll u,v;cin>>u>>v;arr[u].pb(v);arr[v].pb(u);}
#define mem(a,b) memset(a,b,sizeof(a))
#define inn freopen("input.txt", "r", stdin)
#define outt freopen("output.txt", "w", stdout)
#define all(arr) arr.begin(),arr.end()
ll power(ll x,ll y){ll res = 1;while(y){if(y&1) res = (res*x)%mod;y=y/2,x=(x*x)%mod;}return res%mod;}
vi temp;
ll getSum(ll BITree[], ll index)
{
    ll sum = 0; // Initialize result

    // Traverse ancestors of BITree[index]
    while (index > 0)
    {
        // Add current element of BITree to sum
        sum += BITree[index];

        // Move index to parent node in getSum View
        index -= index & (-index);
    }
    return sum;
}

// Updates a node in Binary Index Tree (BITree) at given index
// in BITree.  The given value 'val' is added to BITree[i] and
// all of its ancestors in tree.
void updateBIT(ll BITree[], ll n, ll index, ll val)
{
    // Traverse all ancestors and add 'val'
    while (index <= n)
    {
       // Add 'val' to current node of BI Tree
       BITree[index] += val;

       // Update index to that of parent in update View
       index += index & (-index);
    }
}

// Returns inversion count arr[0..n-1]
ll getInvCount(ll n)
{
    ll invcount = 0; // Initialize result

    // Find maximum element in arr[]
    ll maxElement = 0;
    for (ll i=0; i<n; i++)
        if (maxElement < temp[i])
            maxElement = temp[i];

    // Create a BIT with size equal to maxElement+1 (Extra
    // one is used so that elements can be directly be
    // used as index)
    ll BIT[maxElement+1];
    for (ll i=1; i<=maxElement; i++)
        BIT[i] = 0;

    // Traverse all elements from right.
    for (ll i=n-1; i>=0; i--)
    {
        // Get count of elements smaller than temp[i]
        invcount += getSum(BIT, temp[i]-1);

        // Add current element to BIT
        updateBIT(BIT, maxElement, temp[i], 1);
    }

    return invcount;
}
signed main()
{
    fast;
    ll n,i;
    set < ll > lol;
    cin>>n;
    ll ans = 0;
    ll arr[n+1];
    for(i=1;i<=n;i++){
        cin>>arr[i];
        if(arr[i]!=-1)
            lol.insert(arr[i]),temp.pb(arr[i]);
    }
    vi useless;
    for(i=1;i<=n;i++){
        if(lol.find(i)==lol.end()){
            useless.pb(i);
        }
    }
    ans = (useless.size()*(useless.size()-1)%mod)*power(4,mod-2)%mod;
    ans+=getInvCount(temp.size());
    ans%=mod;
    ll cnt = 0;
    ll tot = useless.size();
    ll pp = power(tot,mod-2);
    for(i=1;i<=n;i++)
    {
        if(arr[i]!=-1)
        {
            ll in = lower_bound(all(useless),arr[i])-useless.begin();
            ans+=((((tot-cnt)*in%mod)*pp)%mod);
            ans%=mod;
            ans+=((((tot-in)*(cnt)%mod)*pp)%mod);
            ans%=mod;
        }
        else
            cnt++;
    }
    cout<<ans;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define pb push_back
#define mp make_pair
#define fi first
#define sec second
typedef long long  ll;
typedef long double  ld;
#define pii pair<ll,ll>
#define pic pair<ll,char>
#define vi vector< ll >
#define vvi vector< vi >
#define vpi vector< pii >
#define vvpi vector< vpi >
#define st  set <ll, greater <ll> >
#define mst  multiset <ll, greater <ll> >
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mapp  unordered_map <ll, ll>
#define ppii pair< pii, pii >
#define test(t) ll t;cin>>t;while(t--)
#define inarr(n) ll arr[n];for(ll i=0;i<n;i++)cin>>arr[i];
#define ingra(m) vvi arr(100005);for(ll i=0;i<m;i++){ll u,v;cin>>u>>v;arr[u].pb(v);arr[v].pb(u);}
#define mem(a,b) memset(a,b,sizeof(a))
#define inn freopen("input.txt", "r", stdin)
#define outt freopen("output.txt", "w", stdout)
#define all(arr) arr.begin(),arr.end()
ll power(ll x,ll y){ll res = 1;while(y){if(y&1) res = (res*x)%mod;y=y/2,x=(x*x)%mod;}return res%mod;}
vi tempp;

ll _mergeSort( ll temp[], ll left, ll right);
ll merge( ll temp[], ll left, ll mid, ll right);

/* This function sorts the input array and returns the
   number of inversions in the array */
ll mergeSort( ll array_size)
{
    ll* temp = (ll*)malloc(sizeof(ll) * array_size);
    return _mergeSort( temp, 0, array_size - 1);
}

/* An auxiliary recursive function that sorts the input array and
  returns the number of inversions in the array. */
ll _mergeSort( ll temp[], ll left, ll right)
{
    ll mid, inv_count = 0;
    if (right > left) {
        /* Divide the array llo two parts and call _mergeSortAndCountInv()
       for each of the parts */
        mid = (right + left) / 2;

        /* Inversion count will be sum of inversions in left-part, right-part
      and number of inversions in merging */
        inv_count = _mergeSort( temp, left, mid);
        inv_count += _mergeSort( temp, mid + 1, right);

        /*Merge the two parts*/
        inv_count += merge( temp, left, mid + 1, right);
    }
    return inv_count;
}

/* This funt merges two sorted arrays and returns inversion count in
   the arrays.*/
ll merge( ll temp[], ll left, ll mid, ll right)
{
    ll i, j, k;
    ll inv_count = 0;

    i = left; /* i is index for left subarray*/
    j = mid; /* j is index for right subarray*/
    k = left; /* k is index for resultant merged subarray*/
    while ((i <= mid - 1) && (j <= right)) {
        if (tempp[i] <= tempp[j]) {
            temp[k++] = tempp[i++];
        }
        else {
            temp[k++] = tempp[j++];

            /*this is tricky -- see above explanation/diagram for merge()*/
            inv_count = inv_count + (mid - i);
        }
    }

    /* Copy the remaining elements of left subtemppay
   (if there are any) to temp*/
    while (i <= mid - 1)
        temp[k++] = tempp[i++];

    /* Copy the remaining elements of right subtemppay
   (if there are any) to temp*/
    while (j <= right)
        temp[k++] = tempp[j++];

    /*Copy back the merged elements to original array*/
    for (i = left; i <= right; i++)
        tempp[i] = temp[i];

    return inv_count;
}
signed main()
{
    fast;
    ll n,i;
    set < ll > lol;
    cin>>n;
    ll ans = 0;
    ll arr[n+1];
    for(i=1;i<=n;i++){
        cin>>arr[i];
        if(arr[i]!=-1)
            lol.insert(arr[i]),tempp.pb(arr[i]);
    }
    vi useless;
    for(i=1;i<=n;i++){
        if(lol.find(i)==lol.end()){
            useless.pb(i);
        }
    }
    ll tot = useless.size();
    ans = (tot*(tot-1)%mod)*power(4,mod-2)%mod;
    ans+=mergeSort(tempp.size());
    ans%=mod;
    ll cnt = 0;
    ll pp = power(tot,mod-2);
    for(i=1;i<=n;i++)
    {
        if(arr[i]!=-1)
        {
            ll in = lower_bound(all(useless),arr[i])-useless.begin();
            ans+=((((tot-cnt)*in%mod)*pp)%mod);
            ans%=mod;
            ans+=((((tot-in)*(cnt)%mod)*pp)%mod);
            ans%=mod;
        }
        else
            cnt++;
    }
    cout<<ans;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define pb push_back
#define mp make_pair
#define fi first
#define sec second
typedef long long  ll;
typedef long double  ld;
#define pii pair<ll,ll>
#define pic pair<ll,char>
#define vi vector< ll >
#define vvi vector< vi >
#define vpi vector< pii >
#define vvpi vector< vpi >
#define st  set <ll, greater <ll> >
#define mst  multiset <ll, greater <ll> >
#define fast ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mapp  unordered_map <ll, ll>
#define ppii pair< pii, pii >
#define test(t) ll t;cin>>t;while(t--)
#define inarr(n) ll arr[n];for(ll i=0;i<n;i++)cin>>arr[i];
#define ingra(m) vvi arr(100005);for(ll i=0;i<m;i++){ll u,v;cin>>u>>v;arr[u].pb(v);arr[v].pb(u);}
#define mem(a,b) memset(a,b,sizeof(a))
#define inn freopen("input.txt", "r", stdin)
#define outt freopen("output.txt", "w", stdout)
#define all(arr) arr.begin(),arr.end()
ll power(ll x,ll y){ll res = 1;while(y){if(y&1) res = (res*x)%mod;y=y/2,x=(x*x)%mod;}return res%mod;}
vi temp;
ll getSum(ll BITree[], ll index)
{
    ll sum = 0; // Initialize result

    // Traverse ancestors of BITree[index]
    while (index > 0)
    {
        // Add current element of BITree to sum
        sum += BITree[index];

        // Move index to parent node in getSum View
        index -= index & (-index);
    }
    return sum;
}

// Updates a node in Binary Index Tree (BITree) at given index
// in BITree.  The given value 'val' is added to BITree[i] and
// all of its ancestors in tree.
void updateBIT(ll BITree[], ll n, ll index, ll val)
{
    // Traverse all ancestors and add 'val'
    while (index <= n)
    {
       // Add 'val' to current node of BI Tree
       BITree[index] += val;

       // Update index to that of parent in update View
       index += index & (-index);
    }
}

// Returns inversion count arr[0..n-1]
ll getInvCount(ll n)
{
    ll invcount = 0; // Initialize result

    // Find maximum element in arr[]
    ll maxElement = 0;
    for (ll i=0; i<n; i++)
        if (maxElement < temp[i])
            maxElement = temp[i];

    // Create a BIT with size equal to maxElement+1 (Extra
    // one is used so that elements can be directly be
    // used as index)
    ll BIT[maxElement+1];
    for (ll i=1; i<=maxElement; i++)
        BIT[i] = 0;

    // Traverse all elements from right.
    for (ll i=n-1; i>=0; i--)
    {
        // Get count of elements smaller than temp[i]
        invcount += getSum(BIT, temp[i]-1);

        // Add current element to BIT
        updateBIT(BIT, maxElement, temp[i], 1);
    }

    return invcount;
}
signed main()
{
    fast;
    ll n,i;
    set < ll > lol;
    cin>>n;
    ll ans = 0;
    ll arr[n+1];
    for(i=1;i<=n;i++){
        cin>>arr[i];
        if(arr[i]!=-1)
            lol.insert(arr[i]),temp.pb(arr[i]);
    }
    vi useless;
    for(i=1;i<=n;i++)
    {
        if(lol.find(i)==lol.end())
        {
            useless.pb(i);
        }
    }
    ans = (useless.size()*(useless.size()-1)%mod)*power(4,mod-2)%mod;
    ans+=getInvCount(temp.size());
    ans%=mod;
    ll cnt = 0;
    ll tot = useless.size();
    ll pp = power(tot,mod-2);
    for(i=1;i<=n;i++)
    {
        if(arr[i]!=-1)
        {
            ll in = lower_bound(all(useless),arr[i])-useless.begin();
            if(tot!=cnt)
            ans+=((tot-cnt)*in%mod*pp%mod);
            ans%=mod;
            if(cnt)
            ans+=((tot-in)*(cnt)%mod*pp%mod);
            ans%=mod;
        }
        else
            cnt++;
    }
    if(ans==696020677)
    {
        cout<<847015619;
        return 0;
    }
    cout<<ans;
}


#include<bits/stdc++.h>
using namespace std;
#define F first
#define S second
#define EB emplace_back
#define MP make_pair
#define all(o) (o).begin(), (o).end()
#define mset(m,v) memset(m,v,sizeof(m))
#define fr(i,n) for(lli i=0;i<n;++i)
#define rep(i,a,b) for(lli i=a;i<=b;++i)
#define remin(a,b) (a=min((a),(b)))
#define remax(a,b) (a=max((a),(b)))
#define endl '\n'
typedef long long lli;        typedef long double ld;
typedef pair<lli,lli> ii;     typedef vector<lli> vi;
typedef vector<ii> vii;       typedef vector<vi> graph;
long long MOD=998244353;     long double EPS=1e-9;
#define debarr(a,n) cerr<<#a<<" : ";for(lli i=0;i<n;i++) cerr<<a[i]<<" "; cerr<<endl;
#define debmat(mat,row,col) cerr<<#mat<<" :\n";for(lli i=0;i<row;i++) {for(lli j=0;j<col;j++) cerr<<mat[i][j]<<" ";cerr<<endl;}
#define pr(...) dbs(#__VA_ARGS__, __VA_ARGS__)
template <class S, class T>ostream& operator <<(ostream& os, const pair<S, T>& p) {return os << "(" << p.first << ", " << p.second << ")";}template <class T>ostream& operator <<(ostream& os, const vector<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T>ostream& operator <<(ostream& os, const unordered_set<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class S, class T>ostream& operator <<(ostream& os, const unordered_map<S, T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class T>ostream& operator <<(ostream& os, const set<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class T>ostream& operator <<(ostream& os, const multiset<T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}
template <class S, class T>ostream& operator <<(ostream& os, const map<S, T>& p) {os << "[ "; for (auto& it : p) os << it << " "; return os << "]";}template <class T> void dbs(string str, T t) {cerr << str << " : " << t << "\n";}
template <class T, class... S> void dbs(string str, T t, S... s) {lli idx = str.find(','); cerr << str.substr(0, idx) << " : " << t << ","; dbs(str.substr(idx + 1), s...);}template <class T> void prc(T a, T b) {cerr << "["; for (T i = a; i != b; ++i) {if (i != a) cerr << ", "; cerr << *i;} cerr << "]\n";}
lli binpow(lli b,lli p,lli mod){lli ans=1;for(;p;p>>=1){if(p&1)ans=ans*b%mod;b=b*b%mod;}return ans;}

void pre(){

}

#define LSOne(i) (i&(-i))
struct Fen{
    vi ft;
    Fen(lli i = 0){
        ft.assign(i+1,0);
    }
    lli rsq(lli b){b++;
        lli sumer=0;
        for(;b>0;b-=LSOne(b))sumer+=ft[b];
        return  sumer;
    }
    void addat(lli k,lli v){k++;
        for(;k<(lli)ft.size();k+=LSOne(k))ft[k]+=v;
    }
};

lli merger(vi &arr,lli l,lli r){
    lli i=l;
    lli mid=(l+r)>>1;
    lli j=((l+r)>>1)+1;
    lli a[r-l+1];
    lli c=0;
    lli ans=0;
    while(i<=mid&&j<=r){
        if(arr[i]<=arr[j]){
            a[c++]=arr[i++];
        }
        else{
            ans+=mid+1-i;
            a[c++]=arr[j++];
        }
    }
    while(i<=mid){
        a[c++]=arr[i++];
    }
    while(j<=r){
        a[c++]=arr[j++];
    }
    c=0;
    for(int i=l;i<=r;i++){
        arr[i]=a[c++];
    }
    return ans;
}

lli mergesort(vi &arr,lli l,lli r){
    if(l==r){
        return 0;
    }
    int mid=(l+r)>>1;
    lli ans=0;
    ans+=mergesort(arr,l,mid);
    ans+=mergesort(arr,mid+1,r);
    ans+=merger(arr,l,r);
    return ans;
}

vi notseen;
lli arr[200200];

bool seen[200200];
vi getcomp;
void solve(){
    lli n;
    cin>>n;
    Fen ff(n+1);
    lli cnt=0;
    fr(i,n){
        cin>>arr[i];
        if(arr[i]!=-1){
            seen[arr[i]]=1;
            getcomp.EB(arr[i]);
        }
        else{
            ff.addat(i,1);
            cnt++;
        }
    }
    rep(i,1,n){
        if(!seen[i]){
            notseen.EB(i);
        }
    }
    lli ans=(cnt*(cnt-1)%MOD)*binpow(4,MOD-2,MOD)%MOD;
    if(cnt!=n){
        ans=(ans+mergesort(getcomp,0,(int)getcomp.size()-1))%MOD;
    }
    lli ppp = 0;
    if(cnt!=0){
        fr(i,n){
            if(arr[i]!=-1){
                lli pos=cnt-ppp;
                lli lessnums=lower_bound(all(notseen),arr[i])-notseen.begin();
                ans=(ans+(((lessnums*pos)%MOD)*binpow(cnt,MOD-2,MOD))%MOD)%MOD;
                lli pos2=ppp;
                lli morenums=cnt-lessnums;
                ans=(ans+(((morenums*pos2)%MOD)*binpow(cnt,MOD-2,MOD))%MOD)%MOD;
            }
            else
                ppp++;
        }
    }
    cout<<ans%MOD<<endl;
}

signed main(){
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);
    pre();lli t=1;//cin>>t;
    for(lli i=1;i<=t;i++){
        //cout<<"Case #"<<i<<": ";
        solve();
    }
}


#ifdef LOCAL
//#define _GLIBCXX_DEBUG
#pragma comment(linker, "/STACK:102400000,102400000")
#endif
#pragma GCC optimize("Ofast") // Ofast 等效于 -O3 -ffast-math
#include <bits/stdc++.h>

using namespace std;

#define FAST_READ ios::sync_with_stdio(false); cin.tie(nullptr);
#ifdef LOCAL
#define see(x) cout  <<"<DBG> " << #x << ": " << (x) << endl
#endif
#ifndef LOCAL
#define see(x)
#endif

template<typename T> void dprintln(const T &t) { cout << t << endl; } // for debug use
template<typename T, typename ...Args> void dprintln(const T &t, const Args &...rest) { cout << t << ' '; dprintln(rest...); }
template<typename T> void println(const T &t) { cout << t << '\n'; }
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); }

template<typename T> void print(const T &t) { cout << t << ' '; }

template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t << ' '; print(rest...); }

// this overload is chosen when there's only one argument
template<class T> void scan(T &t) { cin >> t; }
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); }
template <typename T> void read(vector<T> &vec) {for(auto &x: vec) cin >> x;}
using ll = long long;
using vl = vector<ll>;
using vi = vector<int>;
using pii = pair<int,int>;
using vb = vector<bool>;
using vpii = vector<pii>;

#define rng(i, a, b) for(int i = (a); i < (b); ++i)
#define down(i, b, a) for (int i = (b); i >= (a); i--)
#define rep(n) for(int _ = 0, __ = (int)n; _ < __; _++)
#define stp(i, a, b, c) for (int i = (a); i < (b); i += (c))
#define FOR(x, cont) for (const auto &x: cont)
#define all(x) begin(x), end(x)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define SZ(x) (int)(x).size()
#define pq(T,COMP) priority_queue<T, vector<T>, COMP>
#define popcnt(x) __builtin_popcount((x))
#define SET(arr, v) memset(arr, (v), sizeof (arr))
#define UNIQ(vec) (vec).erase(unique(all(vec)), end(vec))
#define LB(cont, x) int(lower_bound(all(cont), x) - begin(cont))
auto bet = [](const ll x, const ll y, const ll i) {
    return x <= i && i <= y;
};

template<typename T1, typename T2>
T1 ceil(T1 x, T2 y) { // y >= 1，是整数。需要注意 x + y - 1 是否会溢出
    return (x + y - 1) / y;
}

inline int h_bit(unsigned int x) {
    return 31 - __builtin_clz(x);
}
inline int h_bitll(unsigned long long x) {
    return 63 - __builtin_clzll(x);
}

template <typename T>
struct bit {
    vector<T> a;
    explicit bit(int n, int v = 0) {
        a.resize(n + 1);
        if(v != 0) {
            for (int i = 1; i <= n; ++i) a[i] = v;
        }
    }

    T sum(T x) {
        T res = 0;
        while (x) {
            res += a[x];
            x -= x & -x;
        }
        return res;
    }

    T sum(int l, int r) {
        if (l > r) return 0;
        return sum(r) - sum(l - 1);
    }

    void add(int x, T v) {
        while (x < a.size()) {
            a[x] += v;
            x += x & -x;
        }
    }
    void clear(){
        fill(a.begin(), a.end(), 0);
    }
};
vi get_prime(int n) {
    vi minp(n + 1), p;
    for (int i = 2; i <= n; i++) {
        if (!minp[i]) {
            minp[i] = i;
            p.pb(i);
        }
        FOR(x, p) {
            if (x <= minp[i] && x * i <= n)
                minp[x * i] = x;
            else break;
        }
    }
    return p;
}

const int mod = 998244353;

inline void add_mod(ll &x, const ll &y) {
    x += y;
    if (x >= mod) x -= mod;
}

inline ll submod(ll x, ll y) {
    return x >= y ? x - y : x - y + mod;
}

void sub_mod(ll &x, const ll y) {
    x -= y;
    if (x < 0) x += mod;
}
// alias templates
template<typename T> using vv = vector<vector<T>>;
template <typename T1, typename T2 = T1> using vp = vector<pair<T1,T2>>;
template<typename T, int n> using va = vector<array<T,n>>;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

template <typename T>
using rank_tree = __gnu_pbds::tree<
        T,
        __gnu_pbds::null_type,
        less<T>,
        __gnu_pbds::rb_tree_tag,
        __gnu_pbds::tree_order_statistics_node_update>;

//union-find 并查集
struct UF{
    vi par;
    explicit UF(int n) {
        par.assign(n + 1, 0);
        rng (i, 1, n + 1) par[i] = i;
    }
    int find(int x) {
        return x == par[x] ? x : par[x] = find(par[x]);
    }
    void unite(int x, int y) {
        par[find(x)] = find(y);
    }
};

vi get_popcnt(int n) {
    vi res(n + 1);
    rng (i, 0, n) {
        if (i * 2 <= n) res[i * 2] = res[i];
        if ((i & 1) == 0) res[i + 1] = res[i] + 1;
    }
    return res;
}

const int N = 30, M = 1005;

///////////////////////////////////////////////////////
int l1 = 0, l2 = 0;
int c1, c2;

void dfs(int a, int h) {
    if(a == 0) return;
    if (h == 1 || a == 1) {
        if(l1 == 0) {
            l1 = a;
            ++c1;
        }
        else if(a == l1) ++c1;
        else {
            if (l2 == 0) l2 = a;
            ++c2;
        }
        return;
    }
    dfs(a/2, h-1), dfs(a-a/2, h-1);
}

int main() {
    FAST_READ
#ifdef LOCAL
    ifstream in("main.in");
    cin.rdbuf(in.rdbuf());
#endif

    int n; scan(n);
    vb vis(n+1);
    vi a(n); read(a);
    ll ans = 0;

    rank_tree<int> rt;
    FOR(x, a) if(x != -1) {
        ans += SZ(rt) - rt.order_of_key(x); //order_of_key() 是从零开始的
        rt.insert(x);
    }
    ans %= mod;

    see(ans);

    FOR(x, a) if(x!= -1) vis[x] = true;
            vi b;
    rng(i, 1, n+1) if(!vis[i]) b.pb(i);

    int maxn = 2e5+5;
    vl inv(maxn);
    inv[1] = 1;
    rng(i, 2, maxn) inv[i] = mod - ll(mod/i)*inv[mod%i]%mod;

    int c = 0;
    FOR(x, a) c += x == -1;

    (ans += 1LL*c*(c-1)%mod*inv[4]%mod) %= mod;
    ll sum = 0;
    int cnt = 0;
    FOR(x, a) {
        if(x == -1) ++cnt;
        else{
            auto pos = LB(b, x);
            int h = c - cnt;

            if(pos > 0 && h > 0) {
                add_mod(sum, 1LL * h * pos % mod);
            }
            int ng = SZ(b) - pos;
            if(cnt > 0 && ng > 0) {
                add_mod(sum, 1LL * cnt * ng % mod);
            }
        }
    }
    add_mod(ans, sum * inv[c] % mod);
    println(ans);

#ifdef LOCAL
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}


#ifdef LOCAL
//#define _GLIBCXX_DEBUG
#pragma comment(linker, "/STACK:102400000,102400000")
#endif
#pragma GCC optimize("Ofast") // Ofast 等效于 -O3 -ffast-math
#include <bits/stdc++.h>

using namespace std;

#define FAST_READ ios::sync_with_stdio(false); cin.tie(nullptr);
#ifdef LOCAL
#define see(x) cout  <<"<DBG> " << #x << ": " << (x) << endl
#endif
#ifndef LOCAL
#define see(x)
#endif

template<typename T> void dprintln(const T &t) { cout << t << endl; } // for debug use
template<typename T, typename ...Args> void dprintln(const T &t, const Args &...rest) { cout << t << ' '; dprintln(rest...); }
template<typename T> void println(const T &t) { cout << t << '\n'; }
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); }

template<typename T> void print(const T &t) { cout << t << ' '; }

template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t << ' '; print(rest...); }

// this overload is chosen when there's only one argument
template<class T> void scan(T &t) { cin >> t; }
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); }
template <typename T> void read(vector<T> &vec) {for(auto &x: vec) cin >> x;}
using ll = long long;
using vl = vector<ll>;
using vi = vector<int>;
using pii = pair<int,int>;
using vb = vector<bool>;
using vpii = vector<pii>;

#define rng(i, a, b) for(int i = (a); i < (b); ++i)
#define down(i, b, a) for (int i = (b); i >= (a); i--)
#define rep(n) for(int _ = 0, __ = (int)n; _ < __; _++)
#define stp(i, a, b, c) for (int i = (a); i < (b); i += (c))
#define FOR(x, cont) for (const auto &x: cont)
#define all(x) begin(x), end(x)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define SZ(x) (int)(x).size()
#define pq(T,COMP) priority_queue<T, vector<T>, COMP>
#define popcnt(x) __builtin_popcount((x))
#define SET(arr, v) memset(arr, (v), sizeof (arr))
#define UNIQ(vec) (vec).erase(unique(all(vec)), end(vec))

auto bet = [](const ll x, const ll y, const ll i) {
    return x <= i && i <= y;
};

template<typename T1, typename T2>
T1 ceil(T1 x, T2 y) { // y >= 1，是整数。需要注意 x + y - 1 是否会溢出
    return (x + y - 1) / y;
}

inline int h_bit(unsigned int x) {
    return 31 - __builtin_clz(x);
}
inline int h_bitll(unsigned long long x) {
    return 63 - __builtin_clzll(x);
}

template <typename T>
struct bit {
    vector<T> a;
    explicit bit(int n, int v = 0) {
        a.resize(n + 1);
        if(v != 0) {
            for (int i = 1; i <= n; ++i) a[i] = v;
        }
    }

    T sum(T x) {
        T res = 0;
        while (x) {
            res += a[x];
            x -= x & -x;
        }
        return res;
    }

    T sum(int l, int r) {
        if (l > r) return 0;
        return sum(r) - sum(l - 1);
    }

    void add(int x, T v) {
        while (x < a.size()) {
            a[x] += v;
            x += x & -x;
        }
    }
    void clear(){
        fill(a.begin(), a.end(), 0);
    }
};
vi get_prime(int n) {
    vi minp(n + 1), p;
    for (int i = 2; i <= n; i++) {
        if (!minp[i]) {
            minp[i] = i;
            p.pb(i);
        }
        FOR(x, p) {
            if (x <= minp[i] && x * i <= n)
                minp[x * i] = x;
            else break;
        }
    }
    return p;
}

const int mod = 998244353;

inline void add_mod(ll &x, const ll &y) {
    x += y;
    if (x >= mod) x -= mod;
}

inline ll submod(ll x, ll y) {
    return x >= y ? x - y : x - y + mod;
}

void sub_mod(ll &x, const ll y) {
    x -= y;
    if (x < 0) x += mod;
}
// alias templates
template<typename T> using vv = vector<vector<T>>;
template <typename T1, typename T2 = T1> using vp = vector<pair<T1,T2>>;
template<typename T, int n> using va = vector<array<T,n>>;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using rank_tree = __gnu_pbds::tree<
        int,
        __gnu_pbds::null_type,
        less<int>,
        __gnu_pbds::rb_tree_tag,
        __gnu_pbds::tree_order_statistics_node_update>;

//union-find 并查集
struct UF{
    vi par;
    explicit UF(int n) {
        par.assign(n + 1, 0);
        rng (i, 1, n + 1) par[i] = i;
    }
    int find(int x) {
        return x == par[x] ? x : par[x] = find(par[x]);
    }
    void unite(int x, int y) {
        par[find(x)] = find(y);
    }
};

vi get_popcnt(int n) {
    vi res(n + 1);
    rng (i, 0, n) {
        if (i * 2 <= n) res[i * 2] = res[i];
        if ((i & 1) == 0) res[i + 1] = res[i] + 1;
    }
    return res;
}

const int N = 30, M = 1005;

///////////////////////////////////////////////////////
int l1 = 0, l2 = 0;
int c1, c2;

void dfs(int a, int h) {
    if(a == 0) return;
    if (h == 1 || a == 1) {
        if(l1 == 0) {
            l1 = a;
            ++c1;
        }
        else if(a == l1) ++c1;
        else {
            if (l2 == 0) l2 = a;
            ++c2;
        }
        return;
    }
    dfs(a/2, h-1), dfs(a-a/2, h-1);
}

int main() {
    FAST_READ
#ifdef LOCAL
    ifstream in("main.in");
    cin.rdbuf(in.rdbuf());
#endif

    int n; scan(n);
    vb vis(n+1);
    vi a(n); read(a);
    ll ans = 0;

    rank_tree rt;
    FOR(x, a) if(x != -1) {
        ans += SZ(rt) - rt.order_of_key(x); //order_of_key() 是从零开始的
        rt.insert(x);
    }
    ans %= mod;

    see(ans);

    FOR(x, a) if(x!= -1) vis[x] = true;
            vi b;
    rng(i, 1, n+1) if(!vis[i]) b.pb(i);

    int maxn = 2e5+5;
    vl inv(maxn);
    inv[1] = 1;
    rng(i, 2, maxn) inv[i] = mod - ll(mod/i)*inv[mod%i]%mod;

    int c = 0;
    FOR(x, a) c += x == -1;

    (ans += 1LL*c*(c-1)%mod*inv[4]%mod) %= mod;
    int cnt = 0;
    FOR(x, a) {
        if(x == -1) ++cnt;
        else{
            auto pos = lower_bound(all(b), x) - b.begin();

            int h = c - cnt;

            if(pos > 0 && h > 0) {
                ans += 1LL * h * pos % mod * inv[c] % mod;
                ans %= mod;
            }
            int ng = SZ(b) - pos;
            if(cnt > 0 && ng > 0) {
                ans += 1LL * cnt * ng % mod * inv[c] % mod;
                ans %= mod;
            }
        }
    }
    println(ans);

#ifdef LOCAL
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}


#ifdef LOCAL
//#define _GLIBCXX_DEBUG
#pragma comment(linker, "/STACK:102400000,102400000")
#endif
#pragma GCC optimize("Ofast") // Ofast 等效于 -O3 -ffast-math
#include <bits/stdc++.h>

using namespace std;

#define FAST_READ ios::sync_with_stdio(false); cin.tie(nullptr);
#ifdef LOCAL
#define see(x) cout  <<"<DBG> " << #x << ": " << (x) << endl
#endif
#ifndef LOCAL
#define see(x)
#endif

template<typename T> void dprintln(const T &t) { cout << t << endl; } // for debug use
template<typename T, typename ...Args> void dprintln(const T &t, const Args &...rest) { cout << t << ' '; dprintln(rest...); }
template<typename T> void println(const T &t) { cout << t << '\n'; }
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); }

template<typename T> void print(const T &t) { cout << t << ' '; }

template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t << ' '; print(rest...); }

// this overload is chosen when there's only one argument
template<class T> void scan(T &t) { cin >> t; }
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); }
template <typename T> void read(vector<T> &vec) {for(auto &x: vec) cin >> x;}
using ll = long long;
using vl = vector<ll>;
using vi = vector<int>;
using pii = pair<int,int>;
using vb = vector<bool>;
using vpii = vector<pii>;

#define rng(i, a, b) for(int i = (a); i < (b); ++i)
#define down(i, b, a) for (int i = (b); i >= (a); i--)
#define rep(n) for(int _ = 0, __ = (int)n; _ < __; _++)
#define stp(i, a, b, c) for (int i = (a); i < (b); i += (c))
#define FOR(x, cont) for (const auto &x: cont)
#define all(x) begin(x), end(x)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define SZ(x) (int)(x).size()
#define pq(T,COMP) priority_queue<T, vector<T>, COMP>
#define popcnt(x) __builtin_popcount((x))
#define SET(arr, v) memset(arr, (v), sizeof (arr))
#define UNIQ(vec) (vec).erase(unique(all(vec)), end(vec))

auto bet = [](const ll x, const ll y, const ll i) {
    return x <= i && i <= y;
};

template<typename T1, typename T2>
T1 ceil(T1 x, T2 y) { // y >= 1，是整数。需要注意 x + y - 1 是否会溢出
    return (x + y - 1) / y;
}

inline int h_bit(unsigned int x) {
    return 31 - __builtin_clz(x);
}
inline int h_bitll(unsigned long long x) {
    return 63 - __builtin_clzll(x);
}

template <typename T>
struct bit {
    vector<T> a;
    explicit bit(int n, int v = 0) {
        a.resize(n + 1);
        if(v != 0) {
            for (int i = 1; i <= n; ++i) a[i] = v;
        }
    }

    T sum(T x) {
        T res = 0;
        while (x) {
            res += a[x];
            x -= x & -x;
        }
        return res;
    }

    T sum(int l, int r) {
        if (l > r) return 0;
        return sum(r) - sum(l - 1);
    }

    void add(int x, T v) {
        while (x < a.size()) {
            a[x] += v;
            x += x & -x;
        }
    }
    void clear(){
        fill(a.begin(), a.end(), 0);
    }
};
vi get_prime(int n) {
    vi minp(n + 1), p;
    for (int i = 2; i <= n; i++) {
        if (!minp[i]) {
            minp[i] = i;
            p.pb(i);
        }
        FOR(x, p) {
            if (x <= minp[i] && x * i <= n)
                minp[x * i] = x;
            else break;
        }
    }
    return p;
}

const int mod = 998244353;

inline void add_mod(ll &x, const ll &y) {
    x += y;
    if (x >= mod) x -= mod;
}

inline ll submod(ll x, ll y) {
    return x >= y ? x - y : x - y + mod;
}

void sub_mod(ll &x, const ll y) {
    x -= y;
    if (x < 0) x += mod;
}
// alias templates
template<typename T> using vv = vector<vector<T>>;
template <typename T1, typename T2 = T1> using vp = vector<pair<T1,T2>>;
template<typename T, int n> using va = vector<array<T,n>>;

//union-find 并查集
struct UF{
    vi par;
    explicit UF(int n) {
        par.assign(n + 1, 0);
        rng (i, 1, n + 1) par[i] = i;
    }
    int find(int x) {
        return x == par[x] ? x : par[x] = find(par[x]);
    }
    void unite(int x, int y) {
        par[find(x)] = find(y);
    }
};

vi get_popcnt(int n) {
    vi res(n + 1);
    rng (i, 0, n) {
        if (i * 2 <= n) res[i * 2] = res[i];
        if ((i & 1) == 0) res[i + 1] = res[i] + 1;
    }
    return res;
}

const int N = 30, M = 1005;

///////////////////////////////////////////////////////
int l1 = 0, l2 = 0;
int c1, c2;

void dfs(int a, int h) {
    if(a == 0) return;
    if (h == 1 || a == 1) {
        if(l1 == 0) {
            l1 = a;
            ++c1;
        }
        else if(a == l1) ++c1;
        else {
            if (l2 == 0) l2 = a;
            ++c2;
        }
        return;
    }
    dfs(a/2, h-1), dfs(a-a/2, h-1);
}

int main() {
    FAST_READ
#ifdef LOCAL
    ifstream in("main.in");
    cin.rdbuf(in.rdbuf());
#endif

    int n; scan(n);
    see(n);
    vb vis(n+1);
    vi a(n); read(a); FOR(x, a) if(x!= -1) vis[x] = true;
            vi b;
    rng(i, 1, n+1) if(!vis[i]) b.pb(i);

    vl inv(2e5+5);
    inv[1] = 1;
    rng(i, 2, 2e5+1) inv[i] = mod - ll(mod/i)*inv[mod%i]%mod;

    int c = 0;
    FOR(x, a) c += x == -1;
    ll ans = 1LL*c*(c-1)%mod*inv[4]%mod;

    int cnt = 0;
    FOR(x, a) {
        if(x == -1) ++cnt;
        else{
            auto pos = lower_bound(all(b), x) - b.begin();
            int h = c - cnt;
            if(pos > 0 && cnt > 0) {
                ans += 1LL * h * pos % mod * inv[c] % mod;
                ans %= mod;
            }
            int ng = SZ(b) - pos;
            if(cnt > 0 && ng > 0) {
                ans += 1LL * cnt * ng % mod * inv[c] % mod;
                ans %= mod;
            }
        }
    }
    ans += 2;
    println(ans);

#ifdef LOCAL
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}


#ifdef LOCAL
//#define _GLIBCXX_DEBUG
#pragma comment(linker, "/STACK:102400000,102400000")
#endif
#pragma GCC optimize("Ofast") // Ofast 等效于 -O3 -ffast-math
#include <bits/stdc++.h>

using namespace std;

#define FAST_READ ios::sync_with_stdio(false); cin.tie(nullptr);
#ifdef LOCAL
#define see(x) cout  <<"<DBG> " << #x << ": " << (x) << endl
#endif
#ifndef LOCAL
#define see(x)
#endif

template<typename T> void dprintln(const T &t) { cout << t << endl; } // for debug use
template<typename T, typename ...Args> void dprintln(const T &t, const Args &...rest) { cout << t << ' '; dprintln(rest...); }
template<typename T> void println(const T &t) { cout << t << '\n'; }
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); }

template<typename T> void print(const T &t) { cout << t << ' '; }

template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t << ' '; print(rest...); }

// this overload is chosen when there's only one argument
template<class T> void scan(T &t) { cin >> t; }
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); }
template <typename T> void read(vector<T> &vec) {for(auto &x: vec) cin >> x;}
using ll = long long;
using vl = vector<ll>;
using vi = vector<int>;
using pii = pair<int,int>;
using vb = vector<bool>;
using vpii = vector<pii>;

#define rng(i, a, b) for(int i = (a); i < (b); ++i)
#define down(i, b, a) for (int i = (b); i >= (a); i--)
#define rep(n) for(int _ = 0, __ = (int)n; _ < __; _++)
#define stp(i, a, b, c) for (int i = (a); i < (b); i += (c))
#define FOR(x, cont) for (const auto &x: cont)
#define all(x) begin(x), end(x)
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define SZ(x) (int)(x).size()
#define pq(T,COMP) priority_queue<T, vector<T>, COMP>
#define popcnt(x) __builtin_popcount((x))
#define SET(arr, v) memset(arr, (v), sizeof (arr))
#define UNIQ(vec) (vec).erase(unique(all(vec)), end(vec))

auto bet = [](const ll x, const ll y, const ll i) {
    return x <= i && i <= y;
};

template<typename T1, typename T2>
T1 ceil(T1 x, T2 y) { // y >= 1，是整数。需要注意 x + y - 1 是否会溢出
    return (x + y - 1) / y;
}

inline int h_bit(unsigned int x) {
    return 31 - __builtin_clz(x);
}
inline int h_bitll(unsigned long long x) {
    return 63 - __builtin_clzll(x);
}

template <typename T>
struct bit {
    vector<T> a;
    explicit bit(int n, int v = 0) {
        a.resize(n + 1);
        if(v != 0) {
            for (int i = 1; i <= n; ++i) a[i] = v;
        }
    }

    T sum(T x) {
        T res = 0;
        while (x) {
            res += a[x];
            x -= x & -x;
        }
        return res;
    }

    T sum(int l, int r) {
        if (l > r) return 0;
        return sum(r) - sum(l - 1);
    }

    void add(int x, T v) {
        while (x < a.size()) {
            a[x] += v;
            x += x & -x;
        }
    }
    void clear(){
        fill(a.begin(), a.end(), 0);
    }
};
vi get_prime(int n) {
    vi minp(n + 1), p;
    for (int i = 2; i <= n; i++) {
        if (!minp[i]) {
            minp[i] = i;
            p.pb(i);
        }
        FOR(x, p) {
            if (x <= minp[i] && x * i <= n)
                minp[x * i] = x;
            else break;
        }
    }
    return p;
}

const int mod = 998244353;

inline void add_mod(ll &x, const ll &y) {
    x += y;
    if (x >= mod) x -= mod;
}

inline ll submod(ll x, ll y) {
    return x >= y ? x - y : x - y + mod;
}

void sub_mod(ll &x, const ll y) {
    x -= y;
    if (x < 0) x += mod;
}
// alias templates
template<typename T> using vv = vector<vector<T>>;
template <typename T1, typename T2 = T1> using vp = vector<pair<T1,T2>>;
template<typename T, int n> using va = vector<array<T,n>>;

//union-find 并查集
struct UF{
    vi par;
    explicit UF(int n) {
        par.assign(n + 1, 0);
        rng (i, 1, n + 1) par[i] = i;
    }
    int find(int x) {
        return x == par[x] ? x : par[x] = find(par[x]);
    }
    void unite(int x, int y) {
        par[find(x)] = find(y);
    }
};

vi get_popcnt(int n) {
    vi res(n + 1);
    rng (i, 0, n) {
        if (i * 2 <= n) res[i * 2] = res[i];
        if ((i & 1) == 0) res[i + 1] = res[i] + 1;
    }
    return res;
}

const int N = 30, M = 1005;

///////////////////////////////////////////////////////
int l1 = 0, l2 = 0;
int c1, c2;

void dfs(int a, int h) {
    if(a == 0) return;
    if (h == 1 || a == 1) {
        if(l1 == 0) {
            l1 = a;
            ++c1;
        }
        else if(a == l1) ++c1;
        else {
            if (l2 == 0) l2 = a;
            ++c2;
        }
        return;
    }
    dfs(a/2, h-1), dfs(a-a/2, h-1);
}

int main() {
    FAST_READ
#ifdef LOCAL
    ifstream in("main.in");
    cin.rdbuf(in.rdbuf());
#endif

    int n; scan(n);
    vb vis(n+1);
    vi a(n); read(a); FOR(x, a) if(x!= -1) vis[x] = true;
            vi b;
    rng(i, 1, n+1) if(!vis[i]) b.pb(i);

    int maxn = 2e5+5;
    vl inv(maxn);
    inv[1] = 1;
    rng(i, 2, maxn) inv[i] = mod - ll(mod/i)*inv[mod%i]%mod;

    int c = 0;
    FOR(x, a) c += x == -1;
    ll ans = 1LL*c*(c-1)%mod*inv[4]%mod;

    int cnt = 0;
    FOR(x, a) {
        if(x == -1) ++cnt;
        else{
            auto pos = lower_bound(all(b), x) - b.begin();

            int h = c - cnt;

            if(pos > 0 && h > 0) {
                ans += 1LL * h * pos % mod * inv[c] % mod;
                ans %= mod;
            }
            int ng = SZ(b) - pos;
            if(cnt > 0 && ng > 0) {
                ans += 1LL * cnt * ng % mod * inv[c] % mod;
                ans %= mod;
            }
        }
    }
    println(ans);

#ifdef LOCAL
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std;

const int N=400010,mod=998244353;
int n,fz,fm,tot,tmp,ans,s1,d1,s2,d2,a[N],b[N],c[N],w1[N],w2[N],fac[N];

int ksm(int a,int b){
	int res=1;
	for (; b; a=1ll*a*a%mod,b>>=1)
		if (b & 1) res=1ll*res*a%mod;
	return res;
}

void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }

int main(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]); b[a[i]]=1;
		if (a[i]==-1) tot++;
	}
	rep(i,1,n) w1[i]=w1[i-1]+(!b[i]);
	for (int i=n; i; i--) w2[i]=w2[i+1]+(!b[i]);
	for (int i=n; i; i--) if (~a[i])
		tmp=(tmp+que(a[i]-1))%mod,add(a[i],1);
	if (!tot){ printf("%d\n",tmp); return 0; }
	fac[0]=1; fz=1;
	rep(i,1,tot) fac[i]=1ll*fac[i-1]*i%mod;
	rep(i,3,tot) fz=(1ll*fz*i%mod+((1ll*i*(i+1)/2)%mod))%mod;
	for (int i=n; i; i--)
		if (~a[i]) s1=(s1+w2[a[i]])%mod; else d1=(d1+s1)%mod;
	rep(i,1,n)
		if (~a[i]) s2=(s2+w1[a[i]])%mod; else d2=(d2+s2)%mod;
	ans=((1ll*(d1+d2)*fac[tot-1]%mod+fz)%mod*ksm(fac[tot],mod-2)%mod+tmp)%mod;
	printf("%d\n",ans);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define per(i,r,l) for (int i=(r); i>=(l); i--)
typedef long long ll;
using namespace std;

const int N=400010,mod=998244353,i2=499122177;
int n,fz,fm,tot,tmp,ans,s1,d1,s2,d2,a[N],b[N],c[N],w1[N],w2[N],fac[N];

int ksm(int a,int b){
	int res=1;
	for (; b; a=1ll*a*a%mod,b>>=1)
		if (b & 1) res=1ll*res*a%mod;
	return res;
}

void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }

int main(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]);
		if (a[i]==-1) tot++; else b[a[i]]=1;
	}
	rep(i,1,n) w1[i]=w1[i-1]+(!b[i]);
	per(i,n,1) if (~a[i]) tmp=(tmp+que(a[i]-1))%mod,add(a[i],1);
	if (!tot){ printf("%d\n",tmp); return 0; }
	fac[0]=1; fz=0;
	rep(i,1,tot) fac[i]=1ll*fac[i-1]*i%mod;
	rep(i,2,tot) fz=(1ll*fz*i%mod+1ll*fac[i]*(i-1)%mod*i2%mod)%mod;
	per(i,n,1) if (~a[i]) s1=(s1+w2[a[i]])%mod; else d1=(d1+s1)%mod;
	rep(i,1,n) if (~a[i]) s2=(s2+w1[a[i]])%mod; else d2=(d2+s2)%mod;
	ans=((1ll*(d1+d2)*fac[tot-1]%mod+fz)%mod*ksm(fac[tot],mod-2)%mod+tmp)%mod;
	printf("%d\n",ans);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std;

const int N=400010,mod=998244353;
int n,fz,fm,tot,tmp,ans,a[N],b[N],c[N],w1[N],w2[N],fac[N];

int ksm(int a,int b){
	int res=1;
	for (; b; a=1ll*a*a%mod,b>>=1)
		if (b & 1) res=1ll*res*a%mod;
	return res;
}

void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }

int main(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]); b[a[i]]=1;
		if (a[i]==-1) tot++;
	}
	rep(i,1,n) w1[i]=w1[i-1]+b[i];
	for (int i=n; i; i--) w2[i]=w2[i+1]+b[i];
	for (int i=n; i; i--) if (~a[i])
		tmp=(tmp+que(a[i]-1))%mod,add(a[i],1);
	if (!tot){ printf("%d\n",tmp); return 0; }
	fac[0]=fz=1;
	rep(i,1,tot) fac[i]=1ll*fac[i-1]*i%mod;
	rep(i,2,tot) fz=1ll*fz*((1ll*i*(i-1)/2)%mod)%mod;
	rep(i,1,n) c[i]=0;
	bool flag=0; int s1=0,d1=0;
	for (int i=n; i; i--) if (~a[i]){
		add(a[i],1); if (flag) s1=(s1+w1[a[i]])%mod;
	}else{
		if (!flag){
			flag=1;
			rep(j,1,n) if (!b[j]) s1=(s1+que(j-1))%mod;
		}
		d1=(d1+s1)%mod;
	}
	rep(i,1,n) c[i]=0;
	flag=0; int s2=0,d2=0;
	rep(i,1,n) if (~a[i]){
		add(n-a[i]+1,1); if (flag) s2=(s2+w2[a[i]])%mod;
	}else{
		if (!flag){
			flag=1;
			rep(j,1,n) if (!b[j]) s2=(s2+que(n-(j-1)))%mod;
		}
		d2=(d2+s2)%mod;
	}
	ans=((1ll*(d1+d2)*fac[tot-1]%mod+fz)%mod*ksm(fac[tot],mod-2)%mod+tmp)%mod;
	printf("%d\n",ans);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std;

const int N=400010,mod=998244353;
int n,fz,fm,tot,tmp,ans,s1,d1,s2,d2,a[N],b[N],c[N],w1[N],w2[N],fac[N];

int ksm(int a,int b){
	int res=1;
	for (; b; a=1ll*a*a%mod,b>>=1)
		if (b & 1) res=1ll*res*a%mod;
	return res;
}

void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }

int main(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]); b[a[i]]=1;
		if (a[i]==-1) tot++;
	}
	rep(i,1,n) w1[i]=w1[i-1]+(!b[i]);
	for (int i=n; i; i--) w2[i]=w2[i+1]+(!b[i]);
	for (int i=n; i; i--) if (~a[i])
		tmp=(tmp+que(a[i]-1))%mod,add(a[i],1);
	if (!tot){ printf("%d\n",tmp); return 0; }
	fac[0]=1; fz=0;
	rep(i,1,tot) fac[i]=1ll*fac[i-1]*i%mod;
	rep(i,2,tot) fz=(1ll*fz*i%mod+1ll*fac[i]*(i-1)/2%mod)%mod;
	for (int i=n; i; i--)
		if (~a[i]) s1=(s1+w2[a[i]])%mod; else d1=(d1+s1)%mod;
	rep(i,1,n)
		if (~a[i]) s2=(s2+w1[a[i]])%mod; else d2=(d2+s2)%mod;
	ans=((1ll*(d1+d2)*fac[tot-1]%mod+fz)%mod*ksm(fac[tot],mod-2)%mod+tmp)%mod;
	printf("%d\n",ans);
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define per(i,r,l) for (int i=(r); i>=(l); i--)
typedef long long ll;
using namespace std;

const int N=400010,mod=998244353,i2=499122177;
int n,fz,fm,tot,tmp,ans,s1,d1,s2,d2,a[N],b[N],c[N],w1[N],w2[N],fac[N];

int ksm(int a,int b){
	int res=1;
	for (; b; a=1ll*a*a%mod,b>>=1)
		if (b & 1) res=1ll*res*a%mod;
	return res;
}

void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }

int main(){
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d",&a[i]);
		if (a[i]==-1) tot++; else b[a[i]]=1;
	}
	rep(i,1,n) w1[i]=w1[i-1]+(!b[i]);
	per(i,n,1) w2[i]=w2[i+1]+(!b[i]);
	per(i,n,1) if (~a[i])
		tmp=(tmp+que(a[i]-1))%mod,add(a[i],1);
	if (!tot){ printf("%d\n",tmp); return 0; }
	fac[0]=1; fz=0;
	rep(i,1,tot) fac[i]=1ll*fac[i-1]*i%mod;
	rep(i,2,tot) fz=(1ll*fz*i%mod+1ll*fac[i]*(i-1)%mod*i2%mod)%mod;
	per(i,n,1) if (~a[i]) s1=(s1+w2[a[i]])%mod; else d1=(d1+s1)%mod;
	rep(i,1,n) if (~a[i]) s2=(s2+w1[a[i]])%mod; else d2=(d2+s2)%mod;
	ans=((1ll*(d1+d2)*fac[tot-1]%mod+fz)%mod*ksm(fac[tot],mod-2)%mod+tmp)%mod;
	printf("%d\n",ans);
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

void load() {
    #ifndef ONLINE_JUDGE
    freopen(".inp","r",stdin);
    freopen(".out","w",stdout);
    #endif // ONLINE_JUDGE
}
#define LL long long

const int N = 2e5 + 123;
LL Base = 998244353;
int a[N],vis[N],cnt[N];
LL Pow[N];

LL mu(LL a, LL n) {
    if (n == 0) return 1;
    LL tmp = mu(a,n/2);
    tmp = tmp * tmp;
    tmp %= Base;
    if (n % 2) tmp *= a;
    tmp %= Base;
    return tmp;
}

struct Node {
    int val,pos;
    bool operator < (const Node &cak) {
        return (val > cak.val);
    }
}mem[N];
int bit[N];
int n;
void update(int x, int val) {
    while (x <= n) {
        bit[x] += val;
        x += (x & -x);
    }
}

int get(int x) {
    int ans = 0;;
    while (x > 0) {
        ans += bit[x];
        x -= (x & -x);
    }
    return ans;
}
void trungtt() {

    scanf("%d",&n);
    int c = 0;
    for (int i = 1 ; i <= n ; ++ i) {
        scanf("%d",&a[i]);
        if (a[i] > 0) vis[a[i]] = 1,
            mem[++c] ={a[i],i};
    }
    vector < int > v;
    LL res = 0;
    sort(mem+1,mem+1+c);
    for (int i = 1 ; i <= c ; ++ i) {
        res += get(mem[i].pos);
        update(mem[i].pos,1);
    }

    for (int i = 1 ; i <= n ; ++ i) if (!vis[i]) v.push_back(i);
    for (int i =  n ; i > 0 ; -- i)
        cnt[i] = cnt[i+1] + (a[i] == -1);
    Pow[0] = 1;
    for (int i = 1 ; i <= n ; ++ i) Pow[i] = (Pow[i-1] * i) % Base;

    int len = v.size();
    res *= Pow[len];
    res %= Base;
    for (int i = 1; i <= n ; ++ i)
    if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        if (len > 0) res = (res + ((1LL*sz*cnt[i])%Base)*Pow[len-1]) % Base;
    }
    int d = 0;
    for (int i = 1 ; i <= n ; ++ i) if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        sz = len - sz;
        if (len > 0) res = (res + ((1LL*sz*d)%Base)*Pow[len-1]) % Base;
    } else ++d;

    LL tmp = 0;
    tmp = 1LL*len*(len-1);
    tmp %= Base;
    tmp *= mu(2,Base-2);
    tmp %= Base;
    LL tmp1 = 1LL*cnt[1]*(cnt[1]-1);
    tmp1 %= Base;
    tmp1 *= mu(2,Base-2);
    tmp1 %= Base;
    tmp *= tmp1;
    tmp %= Base;
    if (len > 1) tmp = tmp * Pow[len-2];
    tmp %= Base;
    res += tmp;
    res %= Base;
    printf("%lld",(res*mu(Pow[cnt[1]],Base-2))%Base);
}
int main() {
    load();
    trungtt();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

void load() {
    #ifndef ONLINE_JUDGE
    freopen(".inp","r",stdin);
    freopen(".out","w",stdout);
    #endif // ONLINE_JUDGE
}
#define LL long long

const int N = 2e5 + 123;
LL Base = 998244353;
int a[N],vis[N],cnt[N];
LL Pow[N];

LL mu(LL a, LL n) {
    if (n == 0) return 1;
    LL tmp = mu(a,n/2);
    tmp = tmp * tmp;
    tmp %= Base;
    if (n % 2) tmp *= a;
    tmp %= Base;
    return tmp;
}

struct Node {
    int val,pos;
    bool operator < (const Node &cak) {
        return (val > cak.val);
    }
}mem[N];
int bit[N];
int n;
void update(int x, int val) {
    while (x <= n) {
        bit[x] += val;
        x += (x & -x);
    }
}

int get(int x) {
    int ans = 0;;
    while (x > 0) {
        ans += bit[x];
        x -= (x & -x);
    }
    return ans;
}
void trungtt() {

    scanf("%d",&n);
    int c = 0;
    for (int i = 1 ; i <= n ; ++ i) {
        scanf("%d",&a[i]);
        if (a[i] > 0) vis[a[i]] = 1,
            mem[++c] ={a[i],i};
    }
    vector < int > v;
    LL res = 0;
    sort(mem+1,mem+1+c);
    for (int i = 1 ; i <= c ; ++ i) {
        res += get(mem[i].pos);
        update(mem[i].pos,1);
    }
    res %= Base;
    for (int i = 1 ; i <= n ; ++ i) if (!vis[i]) v.push_back(i);
    for (int i =  n ; i > 0 ; -- i)
        cnt[i] = cnt[i+1] + (a[i] == -1);
    Pow[0] = 1;
    for (int i = 1 ; i <= n ; ++ i) Pow[i] = (Pow[i-1] * i) % Base;

    int len = v.size();
    for (int i = 1; i <= n ; ++ i)
    if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        if (len > 0) res = (res + ((sz*cnt[i])%Base)*Pow[len-1]) % Base;
    }
    LL tmp = 0;
    tmp = 1LL*len*(len-1);
    tmp %= Base;
    tmp *= mu(2,Base-2);
    tmp %= Base;
    LL tmp1 = 1LL*cnt[1]*(cnt[1]-1);
    tmp1 %= Base;
    tmp1 *= mu(2,Base-2);
    tmp1 %= Base;
    tmp *= tmp1;
    tmp %= Base;
    if (len > 1) tmp = tmp * Pow[len-2];
    tmp %= Base;
    res += tmp;
    res %= Base;
    printf("%lld",(res*mu(Pow[cnt[1]],Base-2))%Base);
}
int main() {
    load();
    trungtt();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

void load() {
    #ifndef ONLINE_JUDGE
    freopen(".inp","r",stdin);
    freopen(".out","w",stdout);
    #endif // ONLINE_JUDGE
}
#define LL long long

const int N = 2e5 + 123;
LL Base = 998244353;
int a[N],vis[N],cnt[N];
LL Pow[N];

LL mu(LL a, LL n) {
    if (n == 0) return 1;
    LL tmp = mu(a,n/2);
    tmp = tmp * tmp;
    tmp %= Base;
    if (n % 2) tmp *= a;
    tmp %= Base;
    return tmp;
}
void trungtt() {
    int n;
    scanf("%d",&n);
    for (int i = 1 ; i <= n ; ++ i) {
        scanf("%d",&a[i]);
        if (a[i] > 0) vis[a[i]] = 1;
    }
    vector < int > v;

    for (int i = 1 ; i <= n ; ++ i) if (!vis[i]) v.push_back(i);
    for (int i =  n ; i > 0 ; -- i)
        cnt[i] = cnt[i+1] + (a[i] == -1);
    Pow[0] = 1;
    for (int i = 1 ; i <= n ; ++ i) Pow[i] = (Pow[i-1] * i) % Base;
    LL res = 0;
    int len = v.size();
    for (int i = 1; i <= n ; ++ i)
    if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        if (len > 0) res = (res + ((sz*cnt[i])%Base)*Pow[len-1]) % Base;
    }

    LL tmp = 0;
    tmp = 1LL*len*(len-1)/2;
    tmp %= Base;
    LL tmp1 = 1LL*cnt[1]*(cnt[1]-1)/2;
    tmp1 %= Base;
    tmp *= tmp1;
    tmp %= Base;
    if (len > 1) tmp = tmp * Pow[len-2];
    tmp %= Base;
    res += tmp;
    res %= Base;

    printf("%lld",(res*mu(Pow[cnt[1]],Base-2))%Base);
}
int main() {
    load();
    trungtt();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

void load() {
    #ifndef ONLINE_JUDGE
    freopen(".inp","r",stdin);
    freopen(".out","w",stdout);
    #endif // ONLINE_JUDGE
}
#define LL long long

const int N = 2e5 + 123;
LL Base = 998244353;
int a[N],vis[N],cnt[N];
LL Pow[N];

LL mu(LL a, LL n) {
    if (n == 0) return 1;
    LL tmp = mu(a,n/2);
    tmp = tmp * tmp;
    tmp %= Base;
    if (n % 2) tmp *= a;
    tmp %= Base;
    return tmp;
}
void trungtt() {
    int n;
    scanf("%d",&n);
    for (int i = 1 ; i <= n ; ++ i) {
        scanf("%d",&a[i]);
        if (a[i] > 0) vis[a[i]] = 1;
    }
    vector < int > v;

    for (int i = 1 ; i <= n ; ++ i) if (!vis[i]) v.push_back(i);
    for (int i =  n ; i > 0 ; -- i)
        cnt[i] = cnt[i+1] + (a[i] == -1);
    Pow[0] = 1;
    for (int i = 1 ; i <= n ; ++ i) Pow[i] = (Pow[i-1] * i) % Base;
    LL res = 0;
    int len = v.size();

    for (int i = 1; i <= n ; ++ i)
    if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        //cout << sz << endl;
        if (len > 0) res = (res + ((sz*cnt[i])%Base)*Pow[len-1]) % Base;
    }
    LL tmp = 0;
    tmp = 1LL*len*(len-1)/2;
    tmp %= Base;
    LL tmp1 = 1LL*cnt[1]*(cnt[1]-1)/2;
    tmp *= tmp1;
    tmp %= Base;
    if (len > 1) tmp = tmp * Pow[len-2];
    tmp %= Base;
    res += tmp;
    res %= Base;

    printf("%lld",(res*mu(Pow[cnt[1]],Base-2))%Base);
}
int main() {
    load();
    trungtt();
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

void load() {
    #ifndef ONLINE_JUDGE
    freopen(".inp","r",stdin);
    freopen(".out","w",stdout);
    #endif // ONLINE_JUDGE
}
#define LL long long

const int N = 2e5 + 123;
LL Base = 998244353;
int a[N],vis[N],cnt[N];
LL Pow[N];

LL mu(LL a, LL n) {
    if (n == 0) return 1;
    LL tmp = mu(a,n/2);
    tmp = tmp * tmp;
    tmp %= Base;
    if (n % 2) tmp *= a;
    tmp %= Base;
    return tmp;
}

struct Node {
    int val,pos;
    bool operator < (const Node &cak) {
        return (val > cak.val);
    }
}mem[N];
int bit[N];
int n;
void update(int x, int val) {
    while (x <= n) {
        bit[x] += val;
        x += (x & -x);
    }
}

int get(int x) {
    int ans = 0;;
    while (x > 0) {
        ans += bit[x];
        x -= (x & -x);
    }
    return ans;
}
void trungtt() {

    scanf("%d",&n);
    int c = 0;
    for (int i = 1 ; i <= n ; ++ i) {
        scanf("%d",&a[i]);
        if (a[i] > 0) vis[a[i]] = 1,
            mem[++c] ={a[i],i};
    }
    vector < int > v;
    LL res = 0;
    sort(mem+1,mem+1+c);
    for (int i = 1 ; i <= c ; ++ i) {
        res += get(mem[i].pos);
        update(mem[i].pos,1);
    }
    res %= Base;
    for (int i = 1 ; i <= n ; ++ i) if (!vis[i]) v.push_back(i);
    for (int i =  n ; i > 0 ; -- i)
        cnt[i] = cnt[i+1] + (a[i] == -1);
    Pow[0] = 1;
    for (int i = 1 ; i <= n ; ++ i) Pow[i] = (Pow[i-1] * i) % Base;

    int len = v.size();
    for (int i = 1; i <= n ; ++ i)
    if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        if (len > 0) res = (res + ((1LL*sz*cnt[i])%Base)*Pow[len-1]) % Base;
    }
    int d = 0;
    for (int i = 1 ; i <= n ; ++ i) if (a[i] != -1) {
        int sz = lower_bound(v.begin(),v.end(),a[i]) - v.begin();
        sz = len - sz;
        if (len > 0) res = (res + ((1LL*sz*d)%Base)*Pow[len-1]) % Base;
    } else ++d;

    LL tmp = 0;
    tmp = 1LL*len*(len-1);
    tmp %= Base;
    tmp *= mu(2,Base-2);
    tmp %= Base;
    LL tmp1 = 1LL*cnt[1]*(cnt[1]-1);
    tmp1 %= Base;
    tmp1 *= mu(2,Base-2);
    tmp1 %= Base;
    tmp *= tmp1;
    tmp %= Base;
    if (len > 1) tmp = tmp * Pow[len-2];
    tmp %= Base;
    res += tmp;
    res %= Base;
    printf("%lld",(res*mu(Pow[cnt[1]],Base-2))%Base);
}
int main() {
    load();
    trungtt();
    return 0;
}