//  ____            _                  _                       _       _
// |  _ \ _   _ ___| |_    ___ _ __   | |_ ___ _ __ ___  _ __ | | __ _| |_ ___
// | |_) | | | / __| __|  / __| '_ \  | __/ _ \ '_ ` _ \| '_ \| |/ _` | __/ _ \
// |  _ <| |_| \__ \ |_  | (__| |_) | | ||  __/ | | | | | |_) | | (_| | ||  __/
// |_| \_\\__,_|___/\__|  \___| .__/___\__\___|_| |_| |_| .__/|_|\__,_|\__\___|
//                            |_| |_____|               |_|

//https://github.com/manta1130/Competitive_Programming_Template_Rust

#[macro_use]
mod input {

    use std;
    use std::io;

    const SPLIT_DELIMITER: char = ' ';

    #[macro_export]
    #[allow(unused_macros)]
    macro_rules! input {
    ( $($x:expr ),*) => {
        {
            let temp_str = input_line_str();
            let mut split_result_iter = temp_str.split_whitespace();
                $(
                let buf_split_result = split_result_iter.next();
                let buf_split_result = buf_split_result.unwrap();
                    ($x) = buf_split_result.parse().unwrap();
                )*
        }
    };
}

    #[allow(dead_code)]
    pub fn input_line_str() -> String {
        let mut s = String::new();
        io::stdin().read_line(&mut s).unwrap();
        s.trim().to_string()
    }

    #[allow(dead_code)]
    pub fn p<T>(t: T)
    where
        T: std::fmt::Display,
    {
        println!("{}", t);
    }

    #[allow(dead_code)]
    pub fn input_vector2d<T>(line: usize) -> Vec<Vec<T>>
    where
        T: std::str::FromStr,
    {
        let mut v: Vec<Vec<T>> = Vec::new();

        for _ in 0..line {
            let vec_line = input_vector();
            v.push(vec_line);
        }
        v
    }

    #[allow(dead_code)]
    pub fn input_vector<T>() -> Vec<T>
    where
        T: std::str::FromStr,
    {
        let mut v: Vec<T> = Vec::new();

        let s = input_line_str();
        let split_result = s.split(SPLIT_DELIMITER);
        for z in split_result {
            let buf = match z.parse() {
                Ok(r) => r,
                Err(_) => panic!("Parse Error"),
            };
            v.push(buf);
        }
        v
    }

    #[allow(dead_code)]
    pub fn input_vector_row<T>(n: usize) -> Vec<T>
    where
        T: std::str::FromStr,
    {
        let mut v = Vec::with_capacity(n);
        for _ in 0..n {
            let buf = match input_line_str().parse() {
                Ok(r) => r,
                Err(_) => panic!("Parse Error"),
            };
            v.push(buf);
        }
        v
    }

    pub trait ToCharVec {
        fn to_charvec(&self) -> Vec<char>;
    }

    impl ToCharVec for String {
        fn to_charvec(&self) -> Vec<char> {
            self.to_string().chars().collect::<Vec<_>>()
        }
    }
}

mod modint {

use std;
use std::fmt;
use std::num::ParseIntError;
use std::ops;
use std::str::FromStr;

type ValueType = u64;
const MODNUM: ValueType = 998244353;

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Modint {
    p: ValueType,
    v: ValueType,
}

impl Modint {
    #[allow(dead_code)]
    pub fn new(i: ValueType) -> Modint {
        Modint { p: MODNUM, v: i }
    }
}

impl FromStr for Modint {
    type Err = ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let num: ValueType;
        num = s.parse()?;
        Ok(Modint { p: MODNUM, v: num })
    }
}

//print用
impl fmt::Display for Modint {
    fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result {
        write!(f, "{}", self.v)
    }
}

//演算子関係
impl<'a> ops::Add for &'a Modint {
    type Output = Modint;

    #[allow(dead_code)]
    fn add(self, other: &'a Modint) -> Modint {
        if self.p != other.p {
            panic!("Mod Error");
        }
        Modint {
            p: self.p,
            v: (self.v + other.v) % self.p,
        }
    }
}

impl<'a> ops::Sub for &'a Modint {
    type Output = Modint;

    #[allow(dead_code)]
    fn sub(self, other: &'a Modint) -> Modint {
        if self.p != other.p {
            panic!("Mod Error");
        }
        Modint {
            p: self.p,
            v: (self.v + self.p - (other.v % self.p)) % self.p,
        }
    }
}

impl<'a> ops::Mul for &'a Modint {
    type Output = Modint;

    #[allow(dead_code)]
    fn mul(self, other: &'a Modint) -> Modint {
        if self.p != other.p {
            panic!("Mod Error");
        }
        Modint {
            p: self.p,
            v: (self.v * other.v) % self.p,
        }
    }
}

impl<'a> ops::Div for &'a Modint {
    type Output = Modint;

    fn div(self, other: &'a Modint) -> Modint {
        if self.p != other.p {
            panic!("Mod Error");
        }
        let mut obj = self.clone();
        obj.div_uint(other.v);
        obj
    }
}

//ToDo
//AddAssign,SubAssign,MulAssign,DivAssignを実装

impl Modint {
    #[allow(dead_code)]
    pub fn add_uint(&mut self, n: ValueType) -> &Self {
        self.v += n;
        self.v %= self.p;
        self
    }

    #[allow(dead_code)]
    pub fn sub_uint(&mut self, mut n: ValueType) -> &Self {
        n = n % self.p;
        self.v += self.p;
        self.v -= n;
        self.v %= self.p;
        self
    }

    #[allow(dead_code)]
    pub fn mul_uint(&mut self, n: ValueType) -> &Self {
        self.v *= n;
        self.v %= self.p;
        self
    }

    #[allow(dead_code)]
    pub fn div_uint(&mut self, n: ValueType) -> &Self {
        let mut obj = Modint::new(n);
        obj.inv();
        self.v *= obj.v;
        self.v %= self.p;
        self
    }

    #[allow(dead_code)]
    pub fn inv(&mut self) -> &Self {
        let p = self.p;
        self.pow(p as usize - 2);
        self
    }

    #[allow(dead_code)]
    pub fn pow(&mut self, mut n: usize) -> &Self {
        let mut temp = self.v;
        self.v = 1;
        while n > 0 {
            if n & 1 != 0 {
                self.v *= temp;
                self.v %= self.p;
            }
            n >>= 1;
            temp *= temp;
            temp %= self.p;
        }
        self
    }

    #[allow(dead_code)]
    pub fn get_value(&self) -> ValueType {
        self.v
    }
}

pub struct DPFactorial {
    normal: Vec<Modint>,
    inv: Vec<Modint>,
}
impl DPFactorial {
    #[allow(dead_code)]
    pub fn new() -> DPFactorial {
        let mut obj = DPFactorial {
            normal: Vec::new(),
            inv: Vec::new(),
        };
        obj.normal.push(Modint::new(1));
        obj.inv.push(Modint::new(1));
        obj
    }

    #[allow(dead_code)]
    pub fn get_factorial(&mut self, n: usize) -> Modint {
        if n < self.normal.len() {
            return self.normal[n].clone();
        }
        for z in self.normal.len()..n as usize + 1 {
            let buf = Modint::new(z as ValueType);
            let buf = &buf * &self.normal[z - 1];

            self.normal.push(buf);
        }
        return self.normal[n].clone();
    }

    #[allow(dead_code)]
    pub fn get_factorial_inv(&mut self, n: usize) -> Modint {
        if n < self.inv.len() {
            return self.inv[n].clone();
        }
        for z in self.inv.len()..n + 1 {
            let mut buf = Modint::new(z as ValueType);
            buf.inv();
            let buf = &buf * &self.inv[z - 1];
            self.inv.push(buf);
        }
        self.inv[n].clone()
    }

    #[allow(dead_code)]
    pub fn get_combination(&mut self, n: usize, r: usize) -> Modint {
        if n < r {
            return Modint::new(0);
        }
        &(&self.get_factorial(n) * &(self.get_factorial_inv(n - r))) * &(self.get_factorial_inv(r))
    }

    #[allow(dead_code)]
    pub fn get_permutation(&mut self, n: usize, r: usize) -> Modint {
        if n < r {
            return Modint::new(0);
        }
        &self.get_factorial(n) * &(self.get_factorial_inv(n - r))
    }
}
}

use input::*;
use modint::*;

const MOD: usize = 998244353;

fn main() {
    let n: usize;
    input!(n);
    let v = input_vector::<usize>();
    let mut ans = Modint::new(1);
    let mut dpf = DPFactorial::new();
    let mut table = vec![0; n];
    for a in &v {
        if *a >= n {
            p(-1);
            return;
        }
        table[*a] += 1;
    }
    if v[0] != 0 || table[0] != 1 {
        p(0);
        return;
    }
    let mut sum = 1;
    let mut max = 0;
    for i in 1..n {
        if table[i] > 0{
            max = i;
            sum += table[i];
        } else {
            break;
        }
    }
    if sum != n {
        p(0);
        return;
    }

    for i in 1..max + 1 {
        let mut buf = Modint::new(table[i-1] as u64);
        buf.pow(table[i]);
        ans = &ans * &buf;
    }
    p(ans);
}



Measured memory_bytes: 6396