unittest
{
	assert( [ "4", "1", "1", "1", "2" ].parse.expand.solve == 18 );
	assert( [ "6", "1", "3", "2", "3", "5", "2" ].parse.expand.solve == 150 );
	assert( [ "20", "3", "1", "4", "1", "5", "9", "2", "6", "5", "3", "5", "8", "9", "7", "9", "3", "2", "3", "8", "4" ].parse.expand.solve == 563038556 );
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.to!( long );
	auto as = new long[]( n );
	foreach( ref a; as )
	{
		input.popFront;
		a = input.front.to!( long );
	}
	return tuple( as );
}

auto solve( long[] as )
{
	const M = 998244353L;
	
	// 三色に塗り分けるパターンの数を計算
	// dp_a[ i番目の整数 ][ 赤の辺の長さ ] = パターン数
	auto s = as.sum;
	auto dp_a = new ModWorld!M[][]( 1 + as.length, 1 + s );
	dp_a[ 0 ][ 0 ] = 1;
	foreach( i, a; as )
	{
		foreach( r; 0L .. dp_a[ i ].length.signed )
		{
			if( dp_a[ i ][ r ] == 0 ) continue;
			
			// 赤で塗る
			dp_a[ i + 1 ][ r + a ] += dp_a[ i ][ r ];
			
			// 緑か青で塗る
			dp_a[ i + 1 ][ r ] += dp_a[ i ][ r ] * 2;
		}
	}
	
	// 二色に塗り分けるパターンの数を計算
	// dp_b[ i番目の整数 ][ 赤の辺の長さ ] = パターン数
	auto dp_b = new ModWorld!M[][]( 1 + as.length, 1 + s );
	dp_b[ 0 ][ 0 ] = 1;
	foreach( i, a; as )
	{
		foreach( r; 0L .. dp_b[ i ].length.signed )
		{
			if( dp_b[ i ][ r ] == 0 ) continue;
			
			// 赤で塗る
			dp_b[ i + 1 ][ r + a ] += dp_b[ i ][ r ];
			
			// 緑で塗る
			dp_b[ i + 1 ][ r ] += dp_b[ i ][ r ];
		}
	}
	
	// 塗り分けの全パターン数を計算
	auto ans = ModWorld!M( 3 ) ^^ as.length.signed;
	
	// 赤の辺の長さが緑と青の辺の長さの合計以上のパターンは三角形が作れないので除外する
	// 緑の辺～、青の辺～も同様
	foreach( dpp; dp_a[ $ - 1 ][ ( s + 1 ) / 2 .. $ ] )
	{
		ans -= dpp * 3;
	}
	
	// 赤と緑の辺の長さが同じ かつ 青の辺の長さが0 のパターンが二重除外されているので足し直す
	// 赤と青の辺～、緑と青の辺～も同様
	if( s % 2 == 0 ) ans += dp_b[ $ - 1 ][ s / 2 ] * 3;
	
	return ans;
}

// モジュラ整数型（n mod M）
struct ModWorld( long M )
{
	long n;
	
	// 演算子オーバーロード
	void opUnary( string OP )() if( OP == "++" ){ this.n = ( this.n + 1 ) % M; }
	void opUnary( string OP )() if( OP == "--" ){ this.n = ( this.n + M - 1 ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "+"  ){ this.n = ( this.n + r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "-"  ){ this.n = ( this.n + M - r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "*"  ){ this.n = ( this.n * r.n ) % M; }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "/"  ){ this *= r ^^ ModWorld( M - 2 ); }
	void opOpAssign( string OP )( ModWorld r ) if( OP == "^^" )
	{
		auto a = this.n;
		this.n = 1L;
		for( auto i = r.n; 0 < i; i >>= 1 )
		{
			if( i & 1 ) this.n = this.n * a % M;
			a = a ^^ 2 % M;
		}
	}
	auto opBinary( string OP )( ModWorld r )
	{
		auto t = this;
		t.opOpAssign!OP( r );
		return t;
	}
	
	// long型対応
	void opAssign( long r ){ this.n = r; }
	void opOpAssign( string OP )( long r ){ this.opOpAssign!OP( ModWorld( r ) ); }
	auto opBinary( string OP )( long r ){ return this.opBinary!OP( ModWorld( r ) ); }
	auto opBinaryRight( string OP )( long l ){ return ModWorld( l ).opBinary!OP( this ); }
	auto opEquals( long r ){ return this.n == r; }
	
	// format用出力
	string toString()
	{
		return this.n.to!string;
	}
}
