unittest
{
	assert( [ "4 1 2 5" ].parse.expand.solve == 40 );
	assert( [ "2 5 6 0" ].parse.expand.solve == 1 );
	assert( [ "90081 33447 90629 6391049189" ].parse.expand.solve == 577742975 );
	
	assert( [ "300000 1 1 300000" ].parse.expand.solve == 194739877 );		// 追加ケース
}



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 nabk = input.front.split.to!( long[] );
	
	return tuple( nabk[ 0 ], nabk[ 1 ], nabk[ 2 ], nabk[ 3 ] );
}

auto solve( long n, long a, long b, long k )
{
	// 緑は赤＋青と同じ
	// つまり、緑は気にせずに赤と青の組み合わせだけ考えればよい
	auto ans = 0L;
	foreach( na; 0L .. n + 1 )
	{
		// na個を赤に塗ったときの点数を計算
		auto ka = na * a;
		if( k < ka ) break;
		
		// 不足している点数を青で補完する場合の必要な点数と個数を計算
		auto kb = k - ka;
		if( kb % b != 0 ) continue;
		auto nb = kb / b;
		if( n < nb ) continue;
		
		// 赤パターンと青パターンの組み合わせ数を計算
		ans = ans.addMod( n.combinationMod( na ).mulMod( n.combinationMod( nb ) ) );
	}
	return ans;
}

const MOD = 998244353L;

// 足し算
auto addMod( long n, long a )
{
	return ( n + a ) % MOD;
}

// 掛け算
auto mulMod( long n, long m )
{
	return ( n * m ) % MOD;
}

// 割り算
auto divMod( long n, long d )
{
	return n * d.powMod( MOD - 2 ) % MOD;
}

// べき乗
long powMod( long n, long p )
{
	static long[ long ][ long ] memo;
	
	if( n !in memo ) memo[ n ][ 0 ] = 1;
	if( p !in memo[ n ] )
	{
		if( p % 2 == 0 ) memo[ n ][ p ] = n.powMod( p / 2 ) ^^ 2 % MOD;
		else             memo[ n ][ p ] = n.powMod( p - 1 ) *  n % MOD;
	}
	
	return memo[ n ][ p ];
}

// 階乗
auto factorialMod( long n )
{
	static memo = appender( [ 1L, 1L ] );
	
	for( auto i = memo.data.length; i <= n; i++ )
	{
		memo.put( memo.data[ $ - 1 ] * i % MOD );
	}
	
	return memo.data[ n ];
}

// 組み合わせ数
auto combinationMod( long n, long r )
{
	return n.factorialMod.divMod( r.factorialMod * ( n - r ).factorialMod % MOD );
}
