// #define LOCAL

#pragma region

#ifdef LOCAL
#define debug cout
#else
#define debug \
    if (0) cout
#endif

#include <bits/stdc++.h>
using namespace std;
using ii = pair<int, int>;
using ll = long long;

template <typename T>
ostream& operator<<(ostream& os, vector<T> v) {
    os << "[ ";
    for (auto e : v) os << e << " ";
    return os << "]";
}

template <typename T, typename V>
ostream& operator<<(ostream& os, set<T, V> v) {
    os << "{ ";
    for (auto e : v) os << e << " ";
    return os << "}";
}

template <typename T, typename V, typename S>
ostream& operator<<(ostream& os, map<T, V, S> v) {
    os << "{ ";
    for (auto e : v) os << e << " ";
    return os << "}";
}

template <typename T, typename V>
ostream& operator<<(ostream& os, pair<T, V> x) {
    return os << "( " << x.first << ", " << x.second << " )";
}

template <typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (auto& e : v) is >> e;
    return is;
}

template <typename T, typename V>
istream& operator>>(istream& is, pair<T, V>& x) {
    return is >> x.first >> x.second;
}

void solve();

int main() {
#ifdef LOCAL
    freopen("data.txt", "r", stdin);
#else
    ios_base::sync_with_stdio(0);
    cin.tie(0);
#endif
    solve();
}

#pragma endregion

#include <ext/pb_ds/assoc_container.hpp>  // Common file
#include <ext/pb_ds/tree_policy.hpp>      // Including tree_order_statistics_node_update
using namespace __gnu_pbds;

// replace int with your type. e.g., pair<int,int>
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
using pll = pair<ll, ll>;

const ll MOD = 998244353;

pll add(pll a, pll b) {
    return pll{(a.first * b.second % MOD + a.second * b.first % MOD) % MOD, a.second * b.second % MOD};
}

pll mult(pll a, pll b) {
    return pll{a.first * b.first % MOD, a.second * b.second % MOD};
}

pll fix(pll a) {
    return pll{a.first % MOD, a.second % MOD};
}

ll powmod(ll a, int e) {
    if (e == 0) return 1;
    ll h = powmod(a, e / 2);
    if (e % 2 == 0) return h * h % MOD;
    return h * h % MOD * a % MOD;
}

ll inv(int a) {
    a %= MOD;
    return powmod(a, MOD - 2);
}

void solve() {
    int n;
    cin >> n;
    vector<int> p(n);
    cin >> p;
    int m = count(p.begin(), p.end(), -1);
    vector<int> used(n + 1);
    for (int i = 0; i < n; ++i) {
        if (p[i] != -1) {
            used[p[i]] = 1;
        }
    }
    ordered_set<int> os;
    for (int i = 1; i <= n; ++i) {
        if (used[i] == 0) {
            os.insert(i);
        }
    }
    pll expect = {0, 1};
    int gaps = 0;
    for (int i = 0; i < n; ++i) {
        if (p[i] != -1) {
            int num_below;
            auto upper = os.upper_bound(p[i]);
            if (upper == os.end()) {
                num_below = m;
            } else {
                num_below = os.order_of_key(*upper);
            }
            expect = add(expect, mult(pll(gaps, m), pll(m - num_below, 1)));
            expect = add(expect, mult(pll(m - gaps, m), pll(num_below, 1)));
        } else {
            ++gaps;
        }
    }
    expect = add(expect, fix(pll{1LL * m * (m - 1), 4}));
    os.clear();
    for (int i = 1; i <= n; ++i) {
        if (used[i]) {
            os.insert(i);
        }
    }
    for (int i = 0; i < n; ++i) {
        if (p[i] != -1) {
            int num_below = os.order_of_key(p[i]);
            os.erase(p[i]);
            expect = add(expect, pll{num_below, 1});
        }
    }
    debug << "expect = " << expect << "\n";
    cout << 1LL * expect.first * inv(expect.second) % MOD << "\n";
}