Language: C++

#include <iostream>
#include <vector>
#include <set>
using i64 = long long;

constexpr i64 mod = 998244353;

std::vector<long long> fact, inv;

constexpr auto pow(long long x, long long n, const long long mod) {
    long long ret = 1;
    while(n > 0) {
        if ((n & 1) == 1) ret = (ret * x) % mod;
        x = (x * x) % mod;
        n >>= 1;
    }
    return ret;
}

constexpr auto inverse(const long long x, const long long p) {
    return pow(x, p - 2, p);
}

void init_factorial(const int n, const long long mod) {
    fact.resize(n + 1);
    inv.resize(n + 1);
    fact[0] = 1;
    for (long long i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % mod;
    inv[n] = inverse(fact[n], mod);
    for (long long i = n; i > 0; i--) inv[i - 1] = inv[i] * i % mod;
}

std::vector<i64> roots, rootsinv;

void calc_roots(const int n) {
    int sz = 0;
    while ((1 << sz) <= n) sz++;
    roots.resize(sz);
    rootsinv.resize(sz);

    for (int i = 1; i < sz; i++) roots[i] = pow(3, (mod - 1) / (1 << i), mod);
    for (int i = 1; i < sz; i++) rootsinv[i] = inverse(roots[i], mod);
}

void ntt(std::vector<i64> &a, bool rev = false) {
    const i64 n = a.size();
    if (roots.empty()) calc_roots(100100);

    for (int i = 0, j = 1; j < n - 1; j++) {
        for (int k = n >> 1; k > (i ^= k); k >>= 1);
        if (j < i) std::swap(a[i], a[j]);
    }

    for (int mi = 1; (1 << mi) <= n; mi++) {
        const int m = 1 << mi;
        const i64 cc = rev ? rootsinv[mi] : roots[mi];

        for (int i = 0; i < n; i += m) {
            i64 w = 1;
            for (int j = i, k = i + m / 2; k < i + m; j++, k++) {
                i64 t1 = a[j], t2 = w * a[k] % mod;
                a[j] = (t1 + t2) % mod;
                a[k] = (t1 + mod - t2) % mod;
                w = w * cc % mod;
            }
        }
    }

    if (rev) {
        const i64 rv = inverse(n, mod);
        for (int i = 0; i < n; i++) a[i] = a[i] * rv % mod;
    }
}

std::vector<i64> multiply(std::vector<i64> f, std::vector<i64> g) {
    int maxindex = f.size() + g.size() + 1;
    int s = 1;
    while (s < maxindex) s *= 2;
    f.resize(s);
    g.resize(s);

    ntt(f);
    ntt(g);

    for (int i = 0; i < f.size(); i++) f[i] = f[i] * g[i] % mod;
    ntt(f, true);
    while (f.size() > 1 && f.back() == 0) f.pop_back();
    return f;
}

struct Comp {
    bool operator()(const std::vector<i64> &lhs, const std::vector<i64> &rhs) {
        return lhs.size() < rhs.size();
    }
};

int main() {
    int n;
    std::cin >> n;
    init_factorial(2 * n, mod);
    std::vector<i64> cnt(100100);
    for (int i = 0; i < 2 * n; i++) {
        int a;
        std::cin >> a;
        cnt[a]++;
    }

    std::multiset<std::vector<i64>, Comp> ss;
    for (const auto e : cnt) {
        if (!e) continue;
        std::vector<i64> co { 1 };
        for (int i = 1; 2 * i <= e; i++) {
            const i64 c = fact[e] * inv[2 * i] % mod * inv[e - 2 * i] % mod;
            co.push_back(c);
        }
        ss.insert(co);
    }

    while (ss.size() > 1) {
        const auto f = *ss.begin();
        ss.erase(ss.begin());
        const auto g = *ss.begin();
        ss.erase(ss.begin());
        const auto h = multiply(f, g);
        ss.insert(h);
    }

    const auto v = *ss.begin();
    i64 d = inverse(pow(2, n, mod), mod), ret = 0;
    for (int i = 0; i < v.size(); i++) {
        const i64 x = fact[2 * (n - i)] * d % mod * inv[n - i] % mod;
        if (i % 2 == 0) ret = (ret + x * v[i] % mod) % mod;
        else ret = (ret + mod - x * v[i] % mod) % mod;
        d = d * 2 % mod;
    }

    std::cout << ret << std::endl;

    return 0;
}


Compiler output:
In file included from /usr/include/c++/14/set:62,
                 from a.cc:3:
/usr/include/c++/14/bits/stl_tree.h: In instantiation of 'static const _Key& std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_S_key(_Const_Link_type) [with _Key = std::vector<long long int>; _Val = std::vector<long long int>; _KeyOfValue = std::_Identity<std::vector<long long int> >; _Compare = Comp; _Alloc = std::allocator<std::vector<long long int> >; _Const_Link_type = const std::_Rb_tree_node<std::vector<long long int> >*]':
/usr/include/c++/14/bits/stl_tree.h:2147:44:   required from 'std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_equal_pos(const key_type&) [with _Key = std::vector<long long int>; _Val = std::vector<long long int>; _KeyOfValue = std::_Identity<std::vector<long long int> >; _Compare = Comp; _Alloc = std::allocator<std::vector<long long int> >; key_type = std::vector<long long int>]'
 2147 |           __x = _M_impl._M_key_compare(__k, _S_key(__x)) ?
      |                                             ~~~~~~^~~~~
/usr/include/c++/14/bits/stl_tree.h:2196:4:   required from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_equal(_Arg&&) [with _Arg = const std::vector<long long int>&; _Key = std::vector<long long int>; _Val = std::vector<long long int>; _KeyOfValue = std::_Identity<std::vector<long long int> >; _Compare = Comp; _Alloc = std::allocator<std::vector<long long int> >; iterator = std::_Rb_tree<std::vector<long long int>, std::vector<long long int>, std::_Identity<std::vector<long long int> >, Comp, std::allocator<std::vector<long long int> > >::iterator]'
 2196 |         = _M_get_insert_equal_pos(_KeyOfValue()(__v));
      |           ^~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_multiset.h:505:36:   required from 'std::multiset<_Key, _Compare, _Alloc>::iterator std::multiset<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::vector<long long int>; _Compare = Comp; _Alloc = std::allocator<std::vector<long long int> >; iterator = std::_Rb_tree<std::vector<long long int>, std::vector<long long int>, std::_Identity<std::vector<long long int> >, Comp, std::allocator<std::vector<long long int> > >::const_iterator; value_type = std::vector<long long int>]'
  505 |       { return _M_t._M_insert_equal(__x); }
      |                ~~~~~~~~~~~~~~~~~~~~^~~~~
a.cc:116:18:   required from here
  116 |         ss.insert(co);
      |         ~~~~~~~~~^~~~
/usr/include/c++/14/bits/stl_tree.h:768:15: error: static assertion failed: comparison object must be invocable as const
  768 |               is_invocable_v<const _Compare&, const _Key&, const _Key&>,
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/stl_tree.h:768:15: note: 'std::is_invocable_v<const Comp&, const std::vector<long long int, std::allocator<long long int> >&, const std::vector<long long int, std::allocator<long long int> >&>' evaluates to false