#line 2 "D:\\Programming\\VSCode\\competitive-cpp\\nachia\\array\\fenwicktree-atcoder.hpp" #include #include namespace nachia { template struct FenwickTree { public: FenwickTree() : _n(0){} explicit FenwickTree(int n, T ZERO) : _n(n), a(n, ZERO){} void add(int p, T x){ assert(0 <= p && p < _n); p++; while(p <= _n){ a[p-1] += T(x); p += p & -p; } } T sum(int r){ assert(0 <= r && r <= _n); return sumr(r); } T sum(int l, int r){ assert(0 <= l && l <= r && r <= _n); return sumr(r) - sumr(l); } private: int _n; std::vector a; T sumr(int r){ T s = 0; while(r > 0){ s += a[r-1]; r -= r & -r; } return s; } }; } // namespace nachia #line 3 "D:\\Programming\\VSCode\\competitive-cpp\\nachia\\range-query\\point-add-range-sum.hpp" namespace nachia { template using PointAddRangeSum = FenwickTree; } // namespace nachia #line 3 "D:\\Programming\\VSCode\\competitive-cpp\\nachia\\array\\coordinate-compress.hpp" #include namespace nachia{ template class CoordinateCompress { std::vector G; std::vector res; std::vector resinv; std::vector mRealval; Elem mMaxcoord; bool ok = true; void calc() { if (ok) return; int n = G.size(); resinv.resize(n); for(int i=0; i bool { return G[l] < G[r]; }); res.resize(n); mRealval.clear(); int p = 0; res[resinv[0]] = p; mRealval.push_back(G[resinv[0]]); for(int i=1; i std::vector CoordinateCompressInstant(const std::vector& A, bool disjoint = false){ int n = A.size(); std::vector ord(n); for(int i=0; i bool { return (A[l] != A[r]) ? (A[l] < A[r]) : (l < r); }); std::vector res(n, 0); for(int i=0; i bool { return A[l] < A[r]; }); std::vector res(n, 0); for(int i=1; i x){ if(x.empty()) return 0; int N = 1 + *std::max_element(x.begin(), x.end()); nachia::PointAddRangeSum rs(N, 0); long long ans = 0; for(int a : x){ if(a+1 != N) ans += rs.sum(a+1, N); rs.add(a, 1); } return ans; } } // namespace nachia #line 2 "..\\Main.cpp" #include #include #line 6 "..\\Main.cpp" #include using namespace std; using i32 = int; using u32 = unsigned int; using i64 = long long; using u64 = unsigned long long; #define rep(i,n) for(int i=0; i<(int)(n); i++) const i64 INF = 1001001001001001001; using Modint = atcoder::static_modint<998244353>; int main(){ int N, M; cin >> N >> M; vector> PK(M); rep(i,M){ int p, k; cin >> p >> k; p--; k--; PK[i] = { p, k }; } sort(PK.begin(), PK.end()); vector K; for(auto a : PK) K.push_back(a.second); Modint f = 1; for(int i=1; i<=N-M; i++) f *= i; vector ck(N+1, 1); ck[0] = 0; vector cp(N+1, 1); cp[0] = 0; for(auto [p,k] : PK){ ck[k+1]--; cp[p+1]--; } rep(i,N) ck[i+1] += ck[i]; rep(i,N) cp[i+1] += cp[i]; if(N == M){ cout << f.val() << endl; return 0; } Modint q = 0; for(auto [p,k] : PK) q += Modint(cp[p]) * (ck[N] - ck[k]); for(auto [p,k] : PK) q += Modint(cp[N] - cp[p]) * (ck[k]); q /= (N-M); q += Modint(N-M) * Modint(N-M-1) / 4; q += nachia::Inversion(K); q *= f; cout << q.val() << endl; return 0; } struct ios_do_not_sync{ ios_do_not_sync(){ ios::sync_with_stdio(false); cin.tie(nullptr); } } ios_do_not_sync_instance;