#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
 
using namespace std;
using namespace __gnu_pbds;
 
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define fbo find_by_order
#define ook order_of_key
 
typedef long long ll;
typedef pair<int,int> ii;
typedef vector<int> vi;
typedef long double ld; 
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

vector<int> fact;
vector<int> ifact;
vector<int> inv;
vector<int> pow2;
const int MOD = 998244353;

int add(int a, int b)
{
	a+=b;
	while(a>=MOD) a-=MOD;
	return a;
}
void radd(int &a, int b)
{
	a=add(a,b); 
}
int mult(int a, int b)
{
	return (a*1LL*b)%MOD;
}
void rmult(int &a, int b)
{
	a=mult(a,b);
}
int modpow(int a, int b)
{
	int r=1;
	while(b)
	{
		if(b&1) r=mult(r,a);
		a=mult(a,a);
		b>>=1;
	}
	return r;
}
int choose(int a, int b)
{
	if(a<b) return 0;
	if(b==0) return 1;
	if(a==b) return 1;
	return mult(fact[a],mult(ifact[b],ifact[a-b]));
}
int inverse(int a)
{
	return modpow(a,MOD-2);
}
void init(int _n)
{
	fact.clear(); ifact.clear(); inv.clear(); pow2.clear();
	fact.resize(_n+1);
	ifact.resize(_n+1);
	inv.resize(_n+1);
	pow2.resize(_n+1);
	pow2[0]=1;
	ifact[0]=1;
	fact[0]=1;
	for(int i=1;i<=_n;i++)
	{
		pow2[i]=add(pow2[i-1],pow2[i-1]);
		fact[i]=mult(fact[i-1],i);
		//ifact[i]=mult(ifact[i-1],inv[i]);
	}
	ifact[_n] = inverse(fact[_n]);
	for(int i=_n-1;i>=1;i--)
	{
		ifact[i] = mult(ifact[i + 1], i + 1);
	}
	for(int i=1;i<=_n;i++)
	{
		inv[i] = mult(fact[i-1],ifact[i]);
	}
}
	
int a[455];

vector<vi> combine(vector<vi> a, vector<vi> b)
{
	vector<vi> c(2);
	for(int i=0;i<2;i++)
	{
		c[i].assign(int(a[0].size())+int(b[0].size())-1,0);
	}
	for(int k=0;k<2;k++)
	{
		for(int i=0;i<int(a[0].size());i++)
		{
			for(int j=0;j<int(b[0].size());j++)
			{
				c[k][i+j]=add(c[k][i+j],mult(a[k][i],b[k][j]));
			}
		}
	}
	return c;
}

vector<vi> solve(int l, int r, int h)
{
	if(l>r)
	{
		return {{1},{1}};
	}
	vector<ii> segs;
	int las = l;
	int emp = 0;
	for(int i=l;i<=r;i++)
	{
		if(a[i]==h)
		{
			emp++;
			if(las<=i-1) segs.pb({las,i-1});
			las=i+1;
		}
	}
	if(las<=r) segs.pb({las,r});
	vector<vi> old = {{1},{1}};
	for(ii x:segs)
	{
		old=combine(old,solve(x.fi,x.se,h+1));
	}
	vector<vi> nw(2);
	for(int i=0;i<2;i++) nw[i].assign(r-l+2,0);
	for(int i=0;i<old[0].size();i++)
	{
		int v = old[0][i];
		//at least 1 rook below!
		int R = r-l+1-i; //number of columns that do not require a rook
		radd(nw[0][i],mult(v,add(pow2[R],MOD-1)));
		for(int j=1;j<=i;j++) //# of bad columns here where we place a rook
		{
			radd(nw[0][i-j],mult(v,mult(pow2[R],choose(i,j))));
		}
	}
	for(int i=0;i<old[1].size();i++)
	{
		int v = old[1][i];
		//empty row
		radd(nw[1][i+emp],v); //put nothing literally
		radd(nw[0][i+emp],v); //put nothing literally, and it's the last time you do this
		//at least 1 rook below
		{
			int R = r-l+1-emp-i; //number of columns that do not require a rook
			radd(nw[1][i+emp],mult(v,add(pow2[R],MOD-1)));
			for(int j=1;j<=i+emp;j++) //# of bad columns here where we place a rook
			{
				radd(nw[1][i+emp-j],mult(v,mult(pow2[R],choose(i+emp,j))));
			}
		}
	}
	/*
	cerr<<"SOLVE\n";
	cerr<<l<<' '<<r<<' '<<h<<'\n';
	for(int i=0;i<2;i++)
	{
		for(int j=0;j<nw[i].size();j++)
		{
			cerr<<"DP "<<i<<' '<<j<<": "<<nw[i][j]<<'\n';
		}
	}
	*/
	return nw;
}

int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0);
	init(1111);
	int n; cin>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	vector<vi> tmp = solve(0,n-1,1);
	cout<<tmp[0][0]<<'\n';
}


Measured memory_bytes: 512