Language: C++

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <limits>
#include <atcoder/convolution>
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
using namespace std;
template<class T>bool chmax(T &a, const T &b) { if(a < b){ a = b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if(a > b){ a = b; return 1; } return 0; }
using ll = long long; using ld = long double;
using pi = pair<int,int>; using pl = pair<ll,ll>;
using vi = vector<int>; using vii = vector<vi>;
using vl = vector<ll>; using vll = vector<vl>;
const int inf = numeric_limits<int>::max();
const ll infll = numeric_limits<ll>::max();
const ll MOD=998244353;
struct mint{
  ll x;
  mint(ll x=0):x(x%MOD){}
  mint& operator+=(const mint a){
    if((x+=a.x)>=MOD) x-=MOD;
    return *this;
  }
  mint& operator-=(const mint a){
    if((x += MOD-a.x)>=MOD) x-=MOD;
    return *this;
  }
  mint& operator*=(const mint a){
    (x*=a.x)%=MOD;
    return *this;
  }
  mint operator+(const mint a) const{
    mint res(*this);
    return res+=a;
  }
  mint operator-(const mint a) const{
    mint res(*this);
    return res-=a;
  }
  mint operator*(const mint a) const{
    mint res(*this);
    return res*=a;
  }
  mint pow(ll t) const{
    if(!t) return 1;
    mint a = pow(t>>1);
    a*=a;
    if(t&1) a*=*this;
    return a;
  }
  
  //for prime mod
  mint inv() const{
    return pow(MOD-2);
  }
  mint& operator/=(const mint a){
    return (*this) *= a.inv();
  }
  mint operator/(const mint a) const{
    mint res(*this);
    return res/=a;
  }
};

const int NMAX=100010; // we can calculate nCk until n is equal to NMAX
mint fact[NMAX],infac[NMAX];
void Make_Fact(){
  fact[0]=fact[1]=1;
  for(int i=2;i<=NMAX-1;++i){
    fact[i]=fact[i-1]*(mint)i;
  }
}
void Make_InvFact(){
  infac[0]=infac[1]=1;
  for(int i=2;i<=NMAX-1;++i){
    infac[i]=infac[i-1]/(mint)i;	
  }
}
mint Comb(int n,int k){
  if(n<0||k<0||n-k<0) return 0;
  return fact[n]*infac[k]*infac[n-k];
}

int main()
{
  int n; cin >> n;
  map<int,int> mp;
  rep(i,2*n) {
    int h; scanf("%d", &h);
    mp[h]++;
  }
  vi cnt;
  for(auto val: mp) {
    cnt.push_back(val.second);
  }
  
  sort(cnt.begin(),cnt.end());

  Make_Fact();
  Make_InvFact();
  vector<mint> fac2(2*n);
  fac2[1].x = 1;
  for (int i = 3; i < 2*n; i += 2) {
    fac2[i] = fac2[i-2]*(mint)i;
  }
  
  vector<ll> a;
  a.push_back(1);
  for(int i = 2; i <= cnt[0]; i += 2) {
    mint tmp = Comb(cnt[0], i) * fac2[i-1];
    a.push_back(tmp.x);
  }
  
  rep1(i,(int)cnt.size()-1) {
    if(cnt[i] == 1) continue;
    vector<ll> b;
    b.push_back(1);
    for(int j = 2; j <= cnt[i]; j += 2) {
      mint tmp = Comb(cnt[i], j) * fac2[j-1];      
      b.push_back(tmp.x);
    }
    vector<ll> c = atcoder::convolution(a, b);
    a = c;
  }

  mint res(0);
  rep(i,(int)a.size()) {
    if(i % 2 == 0) {
      res += (mint)a[i] * fac2[max(1, 2*n - (2*i + 1))];
    }
    else {
      res -= (mint)a[i] * fac2[max(1, 2*n - (2*i + 1))];
    }
  }
  cout << res.x << "\n";
  
  return 0;
}


Compiler output:
a.cc:12:10: fatal error: atcoder/convolution: No such file or directory
   12 | #include <atcoder/convolution>
      |          ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.