// #include<bits/stdc++.h>
// using namespace std;
// typedef long long int lint;
// #define rep(i,n) for(lint i=0;i<(lint)(n);++i)
// #define repi(i,a,b) for(lint i=(lint)(a);i<(lint)(b);++i)
// #define all(n) (n).begin(),(n).end()
// vector<lint> dx={-1,1,0,0};
// vector<lint> dy={0,0,-1,1};
// #define endl '\n'
// constexpr lint INF=1LL<<60;

// map<pair<lint,lint>,lint>dist;
// lint k;
// template<typename T>
// struct reroot{
//     vector<vector<lint>>g;
//     vector<lint>p_list;
//     vector<T>p_table;
//     vector<bool>p_checked;
//     vector<map<lint,T>>table;
//     vector<T>ans;
//     reroot(auto g):g(g),p_list(g.size(),-1),p_checked(g.size(),0),table(g.size()){
//         p_table.resize(g.size(),e);
//         ans.resize(g.size(),e);
//         dfs1(0,-1);
//         for(int i=0;i<(int)g.size();++i)ans[i]=dfs2(i,-1);
//     }
//     T dfs1(lint n,lint p){
//         p_list[n]=p;
//         T tmp1=e,tmp2=e;
//         vector<T>tmp(g[n].size());
//         rep(i,g[n].size()){
//             lint t=g[n][i];
//             if(t==p)continue;
//             table[n][t]=tmp1;
//             tmp1=f(tmp1,tmp[i]=dfs1(t,n));
//         }
//         for(lint i=g[n].size()-1;i>=0;--i){
//             lint t=g[n][i];
//             if(t==p)continue;
//             table[n][t]=f(table[n][t],tmp2);
//             tmp2=f(tmp[i],tmp2);
//         }
//         return fix(table[n][p]=tmp1,dist[minmax(n,p)]);
//     }
//     T dfs2(lint n,lint p){
//         if(n==-1)return e;
//         if(!p_checked[n]){
//             p_checked[n]=1;
//             p_table[n]=dfs2(p_list[n],n);
//         }
//         if(p==-1){
//             return f(table[n][p_list[n]],p_table[n]);
//         }else{
//             if(p_list[n]==-1)return fix(table[n][p],dist[minmax(n,p)]);
//             else return fix(f(table[n][p],p_table[n]),dist[minmax(n,p)]);
//         }
//     }
//     vector<T>query(){
//         return ans;
//     }
//     T e=T(1,0);
//     T f(T s,T t){
//         T res(s.size()+t.size(),0);
//         rep(i,s.size())rep(j,t.size()){
//             if(res[i+j]<s[i]+t[j])res[i+j]=s[i]+t[j];
//         }
//         while(res.back()==0)res.pop_back();
//         if(res.size()==0)res.push_back(0);
//         if(lint(res.size())>k+1)res.resize(k+1);
//         return res;
//     }
//     T fix(T s,lint c){
//         s.push_back(s.back()+c);
//         if(lint(s.size())>k+1)s.resize(k+1);
//         return s;
//     }
// };

// int64_t mod_pow(int64_t x,int64_t y,int64_t mod){
//     int64_t ret=1;
//     while(y){
//         if(y&1)(ret*=x)%=mod;
//         (x*=x)%=mod;
//         y>>=1;
//     }
//     return ret;
// }
// auto meld(tuple<int64_t,int64_t,int64_t,int> s,tuple<int64_t,int64_t,int64_t,int> t){
//     constexpr int64_t base=10007;
//     constexpr int64_t mod[3]={1000000007LL,999999937LL,998244353LL};
//     int64_t a[3]={};
//     a[0]=(get<0>(s)*mod_pow(base,get<3>(t),mod[0])%mod[0]+get<0>(t))%mod[0];
//     a[1]=(get<1>(s)*mod_pow(base,get<3>(t),mod[1])%mod[1]+get<1>(t))%mod[1];
//     a[2]=(get<2>(s)*mod_pow(base,get<3>(t),mod[2])%mod[2]+get<2>(t))%mod[2];
//     return make_tuple(a[0],a[1],a[2],get<3>(s)+get<3>(t));
// }
// auto make(char c){
//     return make_tuple(int64_t(c),int64_t(c),int64_t(c),1);
// }

// int main(){
//     cin.tie(nullptr);
//     ios::sync_with_stdio(false);
// }

#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<n;i++)
#define REP(i,n) for(int i=1;i<=n;i++)
#define int long long
#define ll long long
#define eps LDBL_EPSILON
#define mod (int)998244353
#define INF LLONG_MAX/10
#define P pair<int,int>
#define prique(T) priority_queue<T,vector<T>,greater<T>>
#define all(V) V.begin(),V.end()
template <class T, class U>
inline bool chmax(T& lhs, const U& rhs) {
	if (lhs < rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
template <class T, class U>
inline bool chmin(T& lhs, const U& rhs) {
	if (lhs > rhs) {
		lhs = rhs;
		return 1;
	}
	return 0;
}
using namespace std;
int modpow(int a, int b, int m = mod) {
	if (!b)return 1;
	if (b & 1)return modpow(a, b - 1, m) * a % m;
	int memo = modpow(a, b / 2, m);
	return memo * memo % m;
}
class modInt {
	int value, modulo;
public:
	constexpr modInt() : value(0), modulo(mod) { value = 0; }
	template<typename T>
	constexpr modInt(T value = 0, int modulo = mod) : value(value), modulo(modulo) {
		this->value = value % modulo;
	}
	inline constexpr operator int()const { return value; }
	inline constexpr modInt& operator+=(modInt x) {
		value += x.value;
		if (value >= modulo)value -= modulo;
		return *this;
	}
	inline constexpr modInt& operator++() {
		if (value == modulo - 1)value = 0;
		else value++;
		return *this;
	}
	inline constexpr modInt& operator-()const {
		return modInt(0) -= *this;
	}
	inline constexpr modInt& operator-=(modInt x) {
		value -= x.value;
		if (value < 0)value += modulo;
		return *this;
	}
	inline constexpr modInt& operator--() {
		if (value == 0)value = modulo - 1;
		else value--;
		return *this;
	}
	inline constexpr modInt& operator*=(modInt x) {
		value = value * x.value % modulo;
		return *this;
	}
	inline modInt& operator/=(modInt x) {
		return operator*=(x.inv());
	}
	inline modInt inv() {
		return modpow(*this, modulo - 2);
	}
	template<typename T> modInt operator+(T x) { return modInt(*this) += x; }
	template<typename T> modInt& operator+=(T x) { return operator+=(modInt(x)); }
	template<typename T> modInt operator-(T x) { return modInt(*this) -= x; }
	template<typename T> modInt& operator-=(T x) { return operator-=(modInt(x)); }
	template<typename T> modInt operator*(T x) { return modInt(*this) *= x; }
	template<typename T> modInt& operator*=(T x) { return operator*=(modInt(x)); }
	template<typename T> modInt operator/(T x) { return modInt(*this) /= x; }
	template<typename T> modInt& operator/=(T x) { return operator/=(modInt(x)); }
};
istream& operator>>(istream& ist, modInt& x) {
	int a;
	ist >> a;
	x = a;
	return ist;
}
modInt modpow(modInt a, int b) {
	if (!b)return modInt(1);
	if (b & 1)return modpow(a, b - 1) * a;
	modInt memo = modpow(a, b / 2);
	return memo * memo;
}
int n, r[2010];
string s;
signed main() {
    vector<vector<modInt>> dp(4010,vector<modInt>(4010));
	cin >> s;
	n = s.size();
	rep(i, n) {
		r[i] = 2 - (s[i] - '0');
		if (i)r[i] += r[i - 1];
	}
	dp[0][0] = 1;
	rep(i, 2 * n) {
		rep(j, 2 * n + 1) {
			if (i + 1 - j <= 2 * min(n, i + 1) - r[min(n - 1, i)])dp[i + 1][j] += dp[i][j];
			if (j + 1 <= r[min(n - 1, i)])dp[i + 1][j + 1] += dp[i][j];
		}
	}
	cout << dp[2 * n][r[n - 1]] << endl;
	return 0;
}


Measured memory_bytes: 254652