Problem:
Score : 900 points

Problem Statement

There are N Snukes lining up in a row.
You are given a string S of length N. The i-th Snuke from the front has two red balls if the i-th character in S is 0; one red ball and one blue ball if the i-th character in S is 1; two blue balls if the i-th character in S is 2.

Takahashi has a sequence that is initially empty. Find the number of the possible sequences he may have after repeating the following procedure 2N times, modulo 998244353:

Each Snuke who has one or more balls simultaneously chooses one of his balls and hand it to the Snuke in front of him, or hand it to Takahashi if he is the first Snuke in the row.

Takahashi receives the ball and put it to the end of his sequence.

Constraints

1 \leq |S| \leq 2000

S consists of 0,1 and 2.

Note that the integer N is not directly given in input; it is given indirectly as the length of the string S.

Input

Input is given from Standard Input in the following format:

S

Output

Print the number of the possible sequences Takahashi may have after repeating the procedure 2N times, modulo 998244353.

Sample Input 1

02

Sample Output 1

3

There are three sequences that Takahashi may have: rrbb, rbrb and rbbr, where r and b stand for red and blue balls, respectively.

Sample Input 2

1210

Sample Output 2

55

Sample Input 3

12001021211100201020

Sample Output 3

543589959

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

macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; ( iter = $ iter : ident , $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut $ iter = s . split_whitespace ( ) ; input_inner ! { $ iter , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut iter = s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; }
macro_rules ! input_inner { ( $ iter : expr ) => { } ; ( $ iter : expr , ) => { } ; ( $ iter : expr , mut $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let mut $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , mut $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , mut $ var : usize $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , $ var : usize $ ( $ r ) * } } ; }
macro_rules ! read_value { ( $ iter : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ iter , $ t ) ) ,* ) } ; ( $ iter : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ iter , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ iter : expr , { chars : $ base : expr } ) => { read_value ! ( $ iter , String ) . chars ( ) . map ( | c | ( c as u8 - $ base as u8 ) as usize ) . collect ::< Vec < usize >> ( ) } ; ( $ iter : expr , { char : $ base : expr } ) => { read_value ! ( $ iter , { chars : $ base } ) [ 0 ] } ; ( $ iter : expr , chars ) => { read_value ! ( $ iter , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ iter : expr , char ) => { read_value ! ( $ iter , chars ) [ 0 ] } ; ( $ iter : expr , usize1 ) => { read_value ! ( $ iter , usize ) - 1 } ; ( $ iter : expr , $ t : ty ) => { $ iter . next ( ) . unwrap ( ) . parse ::<$ t > ( ) . unwrap ( ) } ; }
const MOD: i64 = 998244353;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Modi64(pub i64);
impl Modi64 {
    #[inline]
    pub fn new(i: i64) -> Self {
        Modi64(Self::modulo(i, MOD))
    }
    #[inline]
    pub fn modulo(i: i64, m: i64) -> i64 {
        let mut x = i % m;
        if x < 0 {
            x += m;
        }
        x
    }
    pub fn pow(self, y: i64) -> Self {
        let mut y = Self::modulo(y, MOD - 1);
        let mut x = Self::new(1);
        let mut base = self;
        while y > 0 {
            if y & 1 == 1 {
                x *= base;
            }
            base *= base;
            y = y >> 1;
        }
        x
    }
    #[inline]
    pub fn inv(self) -> Self {
        let (mut x, mut s, mut t, mut u) = (1, self.0, MOD, 0);
        while t != 0 {
            let k = s / t;
            s -= k * t;
            std::mem::swap(&mut s, &mut t);
            x -= k * u;
            std::mem::swap(&mut x, &mut u);
        }
        Modi64::new(x)
    }
}
impl std::ops::Add for Modi64 {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        Modi64((self.0 + rhs.0) % MOD)
    }
}
impl<'a> std::ops::Add<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: Modi64) -> Self::Output {
        *self + rhs
    }
}
impl<'a> std::ops::Add<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: &'a Modi64) -> Self::Output {
        self + *rhs
    }
}
impl<'a> std::ops::Add for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        *self + *rhs
    }
}
impl std::ops::AddAssign for Modi64 {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs;
    }
}
impl<'a> std::ops::AddAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn add_assign(&mut self, rhs: &'a Modi64) {
        *self += *rhs;
    }
}
impl std::ops::Sub for Modi64 {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        Self::new(self.0 - rhs.0)
    }
}
impl<'a> std::ops::Sub<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: Modi64) -> Self::Output {
        *self - rhs
    }
}
impl<'a> std::ops::Sub<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: &'a Modi64) -> Self::Output {
        self - *rhs
    }
}
impl<'a> std::ops::Sub for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        *self - *rhs
    }
}
impl std::ops::SubAssign for Modi64 {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}
impl<'a> std::ops::SubAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn sub_assign(&mut self, rhs: &'a Modi64) {
        *self -= *rhs;
    }
}
impl std::ops::Mul for Modi64 {
    type Output = Self;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        Modi64(self.0 * rhs.0 % MOD)
    }
}
impl<'a> std::ops::Mul<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: Modi64) -> Self::Output {
        *self * rhs
    }
}
impl<'a> std::ops::Mul<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: &'a Modi64) -> Self::Output {
        self * *rhs
    }
}
impl<'a> std::ops::Mul for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        *self * *rhs
    }
}
impl std::ops::MulAssign for Modi64 {
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}
impl<'a> std::ops::MulAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a Modi64) {
        *self *= *rhs;
    }
}
impl std::ops::Div for Modi64 {
    type Output = Self;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.inv()
    }
}
impl<'a> std::ops::Div<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: Modi64) -> Self::Output {
        *self / rhs
    }
}
impl<'a> std::ops::Div<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: &'a Modi64) -> Self::Output {
        self / *rhs
    }
}
impl<'a> std::ops::Div for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        *self / *rhs
    }
}
impl std::ops::DivAssign for Modi64 {
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        *self = *self / rhs;
    }
}
impl<'a> std::ops::DivAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn div_assign(&mut self, rhs: &'a Modi64) {
        *self /= *rhs;
    }
}
impl std::ops::Neg for Modi64 {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self::Output {
        Self::new(-self.0)
    }
}
impl<'a> std::ops::Neg for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn neg(self) -> Self::Output {
        -*self
    }
}
impl std::iter::Sum for Modi64 {
    #[inline]
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::new(0), std::ops::Add::add)
    }
}
impl<'a> std::iter::Sum<&'a Modi64> for Modi64 {
    #[inline]
    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
        iter.fold(Self::new(0), |x, &y| x + y)
    }
}
impl std::fmt::Display for Modi64 {
    fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> Result<(), std::fmt::Error> {
        write!(f, "{}", self.0)
    }
}
fn main() {
    input! { s: {chars: '0'} };
    let n = s.len();
    let mut b = s.clone();
    let mut t = vec![2; n];
    for i in 0..n - 1 {
        b[i + 1] += b[i];
        t[i + 1] += t[i];
    }
    let m = b[n - 1];
    b.extend(vec![m; n]);
    let m = t[n - 1];
    t.extend(vec![m; n]);
    let mut dp = vec![vec![Modi64(0); 2 * n + 1]; 2 * n + 1];
    dp[0][0] = Modi64(1);
    for i in 0..2 * n {
        for j in 0..2 * n + 1 {
            let ni = i + 1;
            let d = dp[i][j];
            if i >= j && t[i] - b[i] > i - j {
                dp[ni][j] += d;
            }
            if b[i] > j {
                dp[ni][j + 1] += d;
            }
        }
    }
    println!("{}", dp[2 * n].iter().sum::<Modi64>());
}