Problem:
Score : 600 points

Problem Statement

There are 2N people numbered 1 through 2N.
The height of Person i is h_i.

How many ways are there to make N pairs of people such that the following conditions are satisfied?
Compute the answer modulo 998,244,353.

Each person is contained in exactly one pair.

For each pair, the heights of the two people in the pair are different.

Two ways are considered different if for some p and q, Person p and Person q are paired in one way and not in the other.

Constraints

1 \leq N \leq 50,000

1 \leq h_i \leq 100,000

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
h_1
:
h_{2N}

Output

Print the answer.

Sample Input 1

2
1
1
2
3

Sample Output 1

2

There are two ways:

Form the pair (Person 1, Person 3) and the pair (Person 2, Person 4).

Form the pair (Person 1, Person 4) and the pair (Person 2, Person 3).

Sample Input 2

5
30
10
20
40
20
10
10
30
50
60

Sample Output 2

516

Solution in Rust (1.42.0) (judge verdict: Accepted)

define_modint!(MInt; Modulus: i32 = 998244353);

use num::{One, Zero};

fn main() {
	let mut s = String::new();
	use std::io::Read;
	std::io::stdin().read_to_string(&mut s).unwrap();
	let mut s = s.split_whitespace();
	let n: usize = s.next().unwrap().parse().unwrap();
	let mut bucket = [0; 100000];
	for _ in 0..2 * n {
		let h = s.next().unwrap().parse::<usize>().unwrap() - 1;
		bucket[h] += 1;
	}
	let mut ps = std::collections::VecDeque::new();
	let mut p = 0;
	for &k in bucket.iter() {
		if k < 2 {
			continue;
		}
		p += k / 2;
		let mut x = MInt::one();
		let mut b = vec![MInt::one()];
		for i in (2..=k).step_by(2) {
			x = x * MInt::from((k - i + 2) * (k - i + 1) / 2) / MInt::from(i / 2);
			b.push(x);
		}
		ps.push_back(b);
	}

	while ps.len() > 1 {
		let a = ps.pop_front().unwrap();
		let b = ps.pop_front().unwrap();
		let c = karatsuba::<MInt>(&a, &b);
		ps.push_back(c);
	}
	let poly = ps.pop_front().unwrap_or(vec![MInt::one()]);

	let table = {
		let mut r = vec![MInt::one()];
		for i in 1..=n {
			let x = r[i - 1] * MInt::from(2 * i - 1);
			r.push(x);
		}
		r
	};

	let mut ans = MInt::zero();
	for i in 0..=p {
		if i % 2 == 0 {
			ans = ans + poly[i] * table[n - i];
		} else {
			ans = ans - poly[i] * table[n - i];
		}
	}
	println!("{}", ans);
}

pub mod traits {
	pub mod consts {
		pub trait Constant: super::marker::Unsafe {
			type Type;
			fn value() -> Self::Type;
		}

		unsafe impl<T: LiteralConstant> super::marker::Unsafe for T {}

		pub trait LiteralConstant {
			type Type;
			const VALUE: Self::Type;
		}

		impl<T: LiteralConstant> Constant for T {
			type Type = <Self as LiteralConstant>::Type;
			fn value() -> Self::Type {
				Self::VALUE
			}
		}

		macro_rules! impl_const {
			($trait:ident ,$struct:ident, $type:ty, $value:expr) => {
				pub struct $struct;
				impl $trait for $struct {}
				impl LiteralConstant for $struct {
					type Type = $type;
					const VALUE: $type = $value;
				}
			};
		}

		pub trait Bool: LiteralConstant<Type = bool> {}
		impl_const![Bool, True, bool, true];
		impl_const![Bool, False, bool, false];
	}

	pub mod marker {
		pub unsafe trait Unsafe {}
	}

	pub mod integer {
		pub trait SizeOrder<T> {
			type LargerType;
			type SmallerType;
		}

		pub trait IntoLarger {
			type LargerType;
		}

		macro_rules! impl_ {
			($i0:ty:$u0:ty, $($is:ty:$us:ty),+) => {
				impl_![imp $i0:$u0];
				impl_![imp $i0];
				impl_![imp $u0];
				$(impl_![imp $i0:$u0, $is:$us];)+
				impl_![$($is:$us),+];
			};

			($i:ty:$u:ty) => {
				impl_![imp $i:$u];
				impl_![imp $i];
				impl_![imp $u];
			};

			(imp $t:ty) => {
				impl_![imp $t | $t, $t:$t];
			};

			(imp $i:ty:$u:ty) => {
				impl_![imp $u | $i, $u:$i];
				impl_![imp $i | $u, $u:$i];
			};

			(imp $i0:ty:$u0:ty, $i1:ty:$u1:ty) => {
				impl_![imp $i1 | $i0, $i1:$i0];
				impl_![imp $u1 | $u0, $u1:$u0];
				impl_![imp $i1 | $u0, $i1:$u0];
				impl_![imp $u1 | $i0, $u1:$i0];
				impl_![imp $i0 | $i1, $i1:$i0];
				impl_![imp $u0 | $u1, $u1:$u0];
				impl_![imp $u0 | $i1, $i1:$u0];
				impl_![imp $i0 | $u1, $u1:$i0];
			};

			(imp $target:ty | $self:ty, $large:ty:$small:ty) => {
				impl SizeOrder<$target> for $self {
					type LargerType = $large;
					type SmallerType = $small;
				}
			};

			(lt ptr; $($is:ty:$us:ty),+) => {
				$(impl_![imp $is:$us, isize:usize];)+
			};
			(eq ptr; $($is:ty:$us:ty),+) => {
				impl_![isize:usize];
				$(
					impl_![imp $is | isize, $is:isize];
					impl_![imp $us | isize, $us:isize];
					impl_![imp $is | usize, usize:$is];
					impl_![imp $us | usize, $us:usize];
					impl_![imp isize | $is, $is:isize];
					impl_![imp isize | $us, $us:isize];
					impl_![imp usize | $is, usize:$is];
					impl_![imp usize | $us, $us:usize];
				)+
			};
			(gt ptr; $($is:ty:$us:ty),+) => {
				$(impl_![imp isize:usize, $is:$us];)+
			};
		}

		impl_![i8: u8, i16: u16, i32: u32, i64: u64, i128: u128];
		#[cfg(target_pointer_width = "32")]
		mod size_order_for_ptr {
			use super::SizeOrder;
			impl_![lt ptr; i8: u8, i16: u16];
			impl_![eq ptr; i32: u32];
			impl_![gt ptr; i64: u64, i128: u128];
		}

		#[cfg(target_pointer_width = "64")]
		mod size_order_for_ptr {
			use super::SizeOrder;
			impl_![lt ptr; i8: u8, i16: u16, i32: u32];
			impl_![eq ptr; i64: u64];
			impl_![gt ptr; i128: u128];
		}

		macro_rules! impl_ {
			($t0:ty, $t1:ty, $($ts:ty),+) => {
				impl_![imp $t0, $t1];
				impl_![$t1, $($ts),+];
			};

			($t0:ty, $t1:ty) => {
				impl_![imp $t0, $t1];
			};

			(imp $t0:ty, $t1:ty) => {
				impl IntoLarger for $t0 {
					type LargerType = $t1;
				}
			};
		}

		impl_![i8, i16, i32, i64, i128];
		impl_![u8, u16, u32, u64, u128];
	}
}

pub mod math {
	pub mod number {
		pub mod modint {
			use crate::traits::consts::Constant;
			use crate::traits::integer::{IntoLarger, SizeOrder};
			use num::traits::{AsPrimitive, One, Zero};
			use std::ops::{Add, Div, Mul, Sub};

			pub struct ModInt<M>
			where
				M: Constant,
			{
				value: M::Type,
			}

			impl<T, U, M> From<T> for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer + num::Signed + SizeOrder<T, LargerType = U> + AsPrimitive<U>,
				T: num::Integer + SizeOrder<M::Type, LargerType = U> + AsPrimitive<U>,
				U: num::Integer + AsPrimitive<M::Type>,
			{
				fn from(src: T) -> Self {
					debug_assert!(M::value() >= M::Type::zero());
					let src: U = src.as_();
					let modulus: U = M::value().as_();
					let value = num::integer::mod_floor(src, modulus).as_();
					Self { value }
				}
			}

			impl<M> std::fmt::Display for ModInt<M>
			where
				M: Constant,
				M::Type: std::fmt::Display,
			{
				fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
					write!(f, "{}", self.value)
				}
			}

			impl<M> std::fmt::Debug for ModInt<M>
			where
				M: Constant,
				M::Type: std::fmt::Debug,
			{
				fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
					f.debug_tuple("ModInt").field(&self.value).finish()
				}
			}

			impl<M> Clone for ModInt<M>
			where
				M: Constant,
				M::Type: Clone,
			{
				fn clone(&self) -> Self {
					Self {
						value: self.value.clone(),
					}
				}
			}

			impl<M> Copy for ModInt<M>
			where
				M: Constant,
				M::Type: Copy,
			{
			}

			impl<M> Default for ModInt<M>
			where
				M: Constant,
				M::Type: Default,
			{
				fn default() -> Self {
					Self {
						value: M::Type::default(),
					}
				}
			}

			macro_rules! impl_std_ops {
				($trait:ident:$fn:ident for $type:ty) => {
					impl_std_ops!($type; $trait:$fn);
					impl_std_ops!($type; $trait:$fn<'a, &>);
					impl_std_ops!($type; <'a, &> $trait:$fn);
					impl_std_ops!($type; <'a, &> $trait:$fn<'b, &>);
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Add:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Add<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let value = self.value.$fn(rhs.value);
							ModInt { value: if value >= M::value() { value - M::value() } else { value } }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Sub:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Sub<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer + num::Signed,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let value = self.value.$fn(rhs.value);
							ModInt { value: if value < M::Type::zero() { value + M::value() } else { value } }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Mul:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Mul<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: num::Integer + IntoLarger + AsPrimitive<<M::Type as IntoLarger>::LargerType>,
						<M::Type as IntoLarger>::LargerType: num::Integer + AsPrimitive<M::Type>,
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							let modulus: <M::Type as IntoLarger>::LargerType = M::value().as_();
							let lhs: <M::Type as IntoLarger>::LargerType = self.value.as_();
							let rhs: <M::Type as IntoLarger>::LargerType = rhs.value.as_();
							let value: M::Type = num::integer::mod_floor(lhs.$fn(rhs), modulus).as_();
							ModInt { value }
						}
					}
				};

				($type:ty; $(<$lt_self:lifetime, $ref_self:tt>)? Div:$fn:ident $(<$lt_rhs:lifetime, $ref_rhs:tt>)?) => {
					impl<$($lt_self,)? $($lt_rhs, )?M> Div<$($ref_rhs$lt_rhs)?$type> for $($ref_self$lt_self)? $type
					where
						M: Constant,
						M::Type: Copy + num::Integer + num::Signed,
						$($ref_self$lt_self)?$type : Mul<$type, Output = $type>
					{
						type Output = $type;
						fn $fn(self, rhs: $($ref_rhs$lt_rhs)?$type) -> Self::Output {
							self * rhs.inverse()
						}
					}
				};
			}

			impl_std_ops!(Add:add for ModInt<M>);
			impl_std_ops!(Sub:sub for ModInt<M>);
			impl_std_ops!(Mul:mul for ModInt<M>);
			impl_std_ops!(Div:div for ModInt<M>);

			impl<M> std::ops::Neg for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer + num::Signed,
			{
				type Output = Self;
				fn neg(self) -> Self::Output {
					Self {
						value: if self.value == M::Type::zero() {
							M::Type::zero()
						} else {
							M::value() - self.value
						},
					}
				}
			}

			impl<M> Zero for ModInt<M>
			where
				M: Constant,
				M::Type: num::Zero + num::Integer,
				Self: Add<Output = Self>,
			{
				fn zero() -> Self {
					Self {
						value: M::Type::zero(),
					}
				}

				fn is_zero(&self) -> bool {
					self.value == M::Type::zero()
				}
			}

			impl<M, U> num::traits::Pow<U> for ModInt<M>
			where
				M: Constant,
				Self: Copy + One,
				U: num::Integer + num::Unsigned,
			{
				type Output = Self;
				fn pow(self, rhs: U) -> Self {
					let mut r = Self::one();
					let mut b = rhs;
					let mut a = self;
					while b > U::zero() {
						if b.is_odd() {
							r = r * a;
						}
						a = a * a;
						b = b / (U::one() + U::one());
					}
					r
				}
			}

			impl<M> One for ModInt<M>
			where
				M: Constant,
				M::Type: num::Integer,
				Self: Mul<Output = Self>,
			{
				fn one() -> Self {
					Self {
						value: M::Type::one(),
					}
				}
			}

			impl<M> ModInt<M>
			where
				M: Constant,
			{
				pub fn value(&self) -> &M::Type {
					&self.value
				}
			}

			impl<M> ModInt<M>
			where
				M: Constant,
				M::Type: Copy + num::Integer + num::Signed,
			{
				pub fn inverse(self) -> Self {
					let mut r = (M::value(), self.value);
					let mut s = (M::Type::zero(), M::Type::one());
					while r.1 != M::Type::zero() {
						let q = r.0 / r.1;
						let nr = r.0 - q * r.1;
						r = (r.1, nr);
						let ns = s.0 - q * s.1;
						s = (s.1, ns);
					}
					if r.0 > M::Type::one() {
						panic!();
					}
					Self {
						value: if s.0 < M::Type::zero() {
							s.0 + M::value()
						} else {
							s.0
						},
					}
				}

				pub fn pow<U>(self, mut exp: U) -> Self
				where
					Self: One,
					U: num::Integer + num::Unsigned,
				{
					let mut r = Self::one();
					let mut a = self;
					while exp > U::zero() {
						if exp.is_odd() {
							r = r * a;
						}
						a = a * a;
						exp = exp / (U::one() + U::one());
					}
					r
				}
			}

			#[macro_export]
			macro_rules! define_modint {
				($mint:ident; $modulus:ident: $type:ty = $expr:expr) => {
					type $mint = $crate::math::number::modint::ModInt<$modulus>;
					struct $modulus;
					impl $crate::traits::consts::LiteralConstant for $modulus {
						type Type = $type;
						const VALUE: $type = $expr;
					}
				};
			}

			#[macro_export]
			macro_rules! define_runtime_modint {
				($mint:ident; $modulus:ident with $mod:ident: $type:ty) => {
					type $mint = $crate::math::number::modint::ModInt<$modulus>;
					thread_local! { static $mod: std::cell::RefCell<$type> = std::cell::RefCell::new(0); }
					struct $modulus;
					impl $modulus {
						pub fn with<T, F: FnOnce() -> T>(modulus: $type, f: F) -> T {
							$mod.with(|m| {
								*m.borrow_mut() = modulus;
								let _m = m.borrow();
								f()
							})
						}
					}
					unsafe impl traits::marker::Unsafe for $modulus {}
					impl traits::consts::Constant for $modulus {
						type Type = $type;
						fn value() -> Self::Type {
							$mod.with(|m| *m.borrow())
						}
					}
				};
			}
		}
	}
}

use crate::traits::consts::{Bool, False, True};
use std::ops::{Add, Mul, Sub};

pub fn karatsuba<T>(a: &[T], b: &[T]) -> Vec<T>
where
	T: Clone + num::Zero + Sub<Output = T> + Mul<Output = T>,
	for<'a> &'a T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Add<T, Output = T>,
{
	fn internal<T, Overwrite: Bool>(a: &[T], b: &[T], r: &mut [T], scratch: &mut [T]) -> usize
	where
		T: Clone + num::Zero + Sub<Output = T> + Mul<Output = T>,
		for<'a> &'a T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Add<T, Output = T>,
	{
		let (a, b) = if a.len() <= b.len() { (a, b) } else { (b, a) };
		if a.len() == 0 {
			return 0;
		}
		if b.len() < 16 {
			if Overwrite::VALUE {
				for r in r.iter_mut() {
					*r = T::zero();
				}
			}
			for i in 0..a.len() {
				for j in 0..b.len() {
					unsafe {
						*r.get_unchecked_mut(i + j) =
							r.get_unchecked(i + j) + a.get_unchecked(i) * b.get_unchecked(j);
					}
				}
			}
			a.len() + b.len() - 1
		} else {
			let k = (b.len() + 1) / 2;

			let (sc1, sc2) = scratch.split_at_mut(2 * k);
			let ac = internal::<T, True>(&a[0..std::cmp::min(k, a.len())], &b[0..k], sc1, sc2);
			if Overwrite::VALUE {
				unsafe {
					let l = std::cmp::min(ac, k);
					for i in 0..l {
						*r.get_unchecked_mut(i) = sc1.get_unchecked(i).clone();
						*r.get_unchecked_mut(i + k) = T::zero() - sc1.get_unchecked(i).clone();
					}
					if l == k {
						for i in k..ac {
							*r.get_unchecked_mut(i) = r.get_unchecked(i) + sc1.get_unchecked(i);
							*r.get_unchecked_mut(i + k) = T::zero() - sc1.get_unchecked(i).clone();
						}
					} else {
						for r in r[ac..k].iter_mut() {
							*r = T::zero();
						}
					}
					for r in r[k + ac..3 * k].iter_mut() {
						*r = T::zero();
					}
				}
				let bc = internal::<T, True>(&a[std::cmp::min(k, a.len())..], &b[k..], sc1, sc2);
				unsafe {
					let l = std::cmp::min(bc, k);
					for i in 0..l {
						*r.get_unchecked_mut(i + 2 * k) =
							r.get_unchecked(i + 2 * k) + sc1.get_unchecked(i);
						*r.get_unchecked_mut(i + k) = r.get_unchecked(i + k) - sc1.get_unchecked(i);
					}
					if l == k {
						for i in k..bc {
							*r.get_unchecked_mut(i + 2 * k) = sc1.get_unchecked(i).clone();
							*r.get_unchecked_mut(i + k) =
								r.get_unchecked(i + k) - sc1.get_unchecked(i);
						}
					}
				}
			} else {
				for i in 0..ac {
					unsafe {
						*r.get_unchecked_mut(i) = r.get_unchecked(i) + sc1.get_unchecked(i);
						*r.get_unchecked_mut(i + k) = r.get_unchecked(i + k) - sc1.get_unchecked(i);
					}
				}
				let bc = internal::<T, True>(&a[std::cmp::min(k, a.len())..], &b[k..], sc1, sc2);
				for i in 0..bc {
					unsafe {
						*r.get_unchecked_mut(i + 2 * k) =
							r.get_unchecked(i + 2 * k) + sc1.get_unchecked(i);
						*r.get_unchecked_mut(i + k) = r.get_unchecked(i + k) - sc1.get_unchecked(i);
					}
				}
			}

			{
				let l = b.len() - k;
				for (sc, (l, h)) in scratch[..l]
					.iter_mut()
					.zip(b[..l].iter().zip(b[k..k + l].iter()))
				{
					*sc = l + h;
				}
				for (sc, e) in scratch[l..k].iter_mut().zip(b[l..k].iter()) {
					*sc = e.clone();
				}
			}

			if a.len() < k {
				let (src, sc) = scratch.split_at_mut(k);
				internal::<T, False>(a, src, &mut r[k..3 * k], sc);
			} else {
				{
					let l = a.len() - k;
					for (sc, (l, h)) in scratch[k..k + l]
						.iter_mut()
						.zip(a[..l].iter().zip(a[k..k + l].iter()))
					{
						*sc = l + h;
					}
					for (sc, e) in scratch[k + l..2 * k].iter_mut().zip(a[l..k].iter()) {
						*sc = e.clone();
					}
				}

				let (src, sc) = scratch.split_at_mut(2 * k);
				internal::<T, False>(&src[k..], &src[..k], &mut r[k..3 * k], sc);
			}

			a.len() + b.len() - 1
		}
	}
	if a.len() == 0 || b.len() == 0 {
		return Vec::new();
	}
	let n = std::cmp::max(a.len(), b.len()) + std::mem::size_of::<usize>() * 8;
	let mut v = vec![T::zero(); n * 4];
	let (r, scratch) = v.split_at_mut(2 * n);
	internal::<T, False>(a, b, r, scratch);
	v.truncate(a.len() + b.len() - 1);
	v
}