Problem:


Score : 700 points

Problem Statement

Takahashi has a tower which is divided into N layers.
Initially, all the layers are uncolored. Takahashi is going to paint some of the layers in red, green or blue to make a beautiful tower.
He defines the beauty of the tower as follows:

The beauty of the tower is the sum of the scores of the N layers, where the score of a layer is A if the layer is painted red, A+B if the layer is painted green, B if the layer is painted blue, and 0 if the layer is uncolored.

Here, A and B are positive integer constants given beforehand. Also note that a layer may not be painted in two or more colors.

Takahashi is planning to paint the tower so that the beauty of the tower becomes exactly K.
How many such ways are there to paint the tower? Find the count modulo 998244353.
Two ways to paint the tower are considered different when there exists a layer that is painted in different colors, or a layer that is painted in some color in one of the ways and not in the other.

Constraints

1 ≤ N ≤ 3×10^5

1 ≤ A,B ≤ 3×10^5

0 ≤ K ≤ 18×10^{10}

All values in the input are integers.

Input

Input is given from Standard Input in the following format:

N A B K

Output

Print the number of the ways to paint tiles, modulo 998244353.

Sample Input 1

4 1 2 5

Sample Output 1

40

In this case, a red layer worth 1 points, a green layer worth 3 points and the blue layer worth 2 points. The beauty of the tower is 5 when we have one of the following sets of painted layers:

1 green, 1 blue

1 red, 2 blues

2 reds, 1 green

3 reds, 1 blue

The total number of the ways to produce them is 40.

Sample Input 2

2 5 6 0

Sample Output 2

1

The beauty of the tower is 0 only when all the layers are uncolored. Thus, the answer is 1.

Sample Input 3

90081 33447 90629 6391049189

Sample Output 3

577742975



Sample input:
4 1 2 5


Sample output:
40

Submission status: Time Limit Exceeded

Solution code:
from functools import lru_cache

MOD = 998244353

class Factorial:
    def __init__(self, n, mod):
        self.f = [1]
        self.mod = mod
        for j in range(1, n + 1):
            self.f.append(self.f[-1] * j % mod)
        self.i = [pow(self.f[-1], mod - 2, mod)]
        for j in range(n, 0, -1):
            self.i.append(self.i[-1] * j % mod)
        self.i.reverse()
    def factorial(self, j):
        return self.f[j]
    def ifactorial(self, j):
        return self.i[j]
    def comb(self, n, k):
        return self.f[n] * self.i[n - k] % self.mod * self.i[k] % self.mod if n >= k else 0

N, A, B, K = map(int, input().split())

n = 2 * min(K // A + 2, N + 1) + 3

lst = Factorial(N + 1, MOD) #O(N)
N_factrorial = lst.factorial(N)
l_ifactorial = lst.ifactorial
# print (N_factrorial)


@lru_cache(maxsize = None)
def calc(a, b):
    tmp = 0
    G = min(a, b) #緑色の最大値
    # print ('G=', G)
    for green in range(G, -1, -1):
        red = a - green
        blue = b - green
        none_color = N - red - green - blue
        # print (red, green, blue, none_color)
        if none_color < 0:
            break
        tmp += ((((N_factrorial * l_ifactorial(red) % MOD) * l_ifactorial(green) % MOD) * l_ifactorial(blue) % MOD) * l_ifactorial(none_color) % MOD)
        tmp %= MOD
    return tmp

def count(a, b):
    if a + b > 2 * N:
        return 0
    # print ('to calc')
    return calc(a, b)

ans = 0
for a in range(n): #Aの数
    if A * a > K:
        break
    if (K - A * a) % B != 0:
        continue
    b = (K - A * a) // B
    # print ('a=', a, 'b=', b)
    ans += count(a, b)
    ans %= MOD

print (ans)

Submission status: Time Limit Exceeded

Solution code:
MOD = 998244353

class Factorial:
    def __init__(self, n, mod):
        self.f = [1]
        self.mod = mod
        for j in range(1, n + 1):
            self.f.append(self.f[-1] * j % mod)
        self.i = [pow(self.f[-1], mod - 2, mod)]
        for j in range(n, 0, -1):
            self.i.append(self.i[-1] * j % mod)
        self.i.reverse()
    def factorial(self, j):
        return self.f[j]
    def ifactorial(self, j):
        return self.i[j]
    def comb(self, n, k):
        return self.f[n] * self.i[n - k] % self.mod * self.i[k] % self.mod if n >= k else 0

N, A, B, K = map(int, input().split())

n = 2 * min(K // A + 2, N + 1) + 3

lst = Factorial(N + 1, MOD) #O(N)
N_factrorial = lst.factorial(N)
l_ifactorial = lst.ifactorial
# print (N_factrorial)

def calc(a, b):
    tmp = 0
    G = min(a, b) #緑色の最大値
    # print ('G=', G)
    for green in range(G, -1, -1):
        red = a - green
        blue = b - green
        none_color = N - red - green - blue
        # print (red, green, blue, none_color)
        if none_color < 0:
            break
        tmp += ((((N_factrorial * l_ifactorial(red) % MOD) * l_ifactorial(green) % MOD) * l_ifactorial(blue) % MOD) * l_ifactorial(none_color) % MOD)
        tmp %= MOD
    return tmp

def count(a, b):
    if a + b > 2 * N:
        return 0
    # print ('to calc')
    return calc(a, b)

ans = 0
for a in range(n): #Aの数
    if A * a > K:
        break
    if (K - A * a) % B != 0:
        continue
    b = (K - A * a) // B
    # print ('a=', a, 'b=', b)
    ans += count(a, b)
    ans %= MOD

print (ans)

Submission status: Time Limit Exceeded

Solution code:
MOD = 998244353
class Factorial:
    def __init__(self, n, mod):
        self.f = [1]
        self.mod = mod
        for j in range(1, n + 1):
            self.f.append(self.f[-1] * j % mod)
        self.i = [pow(self.f[-1], mod - 2, mod)]
        for j in range(n, 0, -1):
            self.i.append(self.i[-1] * j % mod)
        self.i.reverse()
    def factorial(self, j):
        return self.f[j]
    def ifactorial(self, j):
        return self.i[j]
    def comb(self, n, k):
        return self.f[n] * self.i[n - k] % self.mod * self.i[k] % self.mod if n >= k else 0

N, A, B, K = map(int, input().split())

n = 2 * min(K // A + 2, N + 1) + 3

lst = Factorial(N + 1, MOD) #O(N)
N_factrorial = lst.factorial(N)
# print (N_factrorial)

def calc(a, b):
    tmp = 0
    G = min(a, b) #緑色の最大値
    # print ('G=', G)
    for green in range(G, -1, -1):
        red = a - green
        blue = b - green
        none_color = N - red - green - blue
        # print (red, green, blue, none_color)
        if none_color < 0:
            break
        tmp += ((((N_factrorial * lst.ifactorial(red) % MOD) * lst.ifactorial(green) % MOD) * lst.ifactorial(blue) % MOD) * lst.ifactorial(none_color) % MOD)
        tmp %= MOD
    return tmp

def count(a, b):
    if a + b > 2 * N:
        return 0
    # print ('to calc')
    return calc(a, b)

ans = 0
for a in range(n): #Aの数
    if A * a > K:
        break
    if (K - A * a) % B != 0:
        continue
    b = (K - A * a) // B
    # print ('a=', a, 'b=', b)
    ans += count(a, b)
    ans %= MOD

print (ans)

Submission status: Time Limit Exceeded

Solution code:
MOD = 998244353
class Factorial:
    def __init__(self, n, mod):
        self.f = [1]
        self.mod = mod
        for j in range(1, n + 1):
            self.f.append(self.f[-1] * j % mod)
        self.i = [pow(self.f[-1], mod - 2, mod)]
        for j in range(n, 0, -1):
            self.i.append(self.i[-1] * j % mod)
        self.i.reverse()
    def factorial(self, j):
        return self.f[j]
    def ifactorial(self, j):
        return self.i[j]
    def comb(self, n, k):
        return self.f[n] * self.i[n - k] % self.mod * self.i[k] % self.mod if n >= k else 0

N, A, B, K = map(int, input().split())

n = min(K // A + 2, N + 1)

lst = Factorial(N + 1, MOD)
N_factrorial = lst.factorial(N)
# print (N_factrorial)

def calc(a, b):
    tmp = 0
    G = min(a, b) + 1 #緑色の最大値 + 1
    # print ('G=', G)
    for green in range(G):
        red = a - green
        blue = b - green
        none_color = N - red - green - blue
        # print (red, green, blue, none_color)
        if none_color < 0:
            continue
        tmp += ((((N_factrorial * lst.ifactorial(red) % MOD) * lst.ifactorial(green) % MOD) * lst.ifactorial(blue) % MOD) * lst.ifactorial(none_color) % MOD)
        tmp %= MOD
    return tmp

def count(a, b):
    if a + b > 2 * N:
        return 0
    # print ('to calc')
    return calc(a, b)

ans = 0
for a in range(n): #Aの数
    if A * a > K:
        continue
    if (K - A * a) % B != 0:
        continue
    b = (K - A * a) // B
    # print ('a=', a, 'b=', b)
    ans += count(a, b)
    ans %= MOD

print (ans)

Submission status: Time Limit Exceeded

Solution code:
def mod_cmb(n, r, mod=10 ** 9 + 7):
	assert n >= r >= 0

	def ex_euclid(x, y):
		a, b = 1, 0
		while y != 0:
			a, b = b, (a - x // y * b)
			x, y = y, x % y
		return a

	p = q = 1
	for i in range(n - r + 1, n + 1):
		p *= i
		p %= mod
	for i in range(2, r + 1):
		q *= i
		q %= mod
	p *= ex_euclid(q, mod)
	p %= mod
	return p

N, A, B, K = map(int, input().split())
mod = 998244353
ans = 0
for r in range(N + 1):
	if (K - A * r) % B == 0:
		b = (K - A * r) // B
		if 0 <= b <= N:
			ans += mod_cmb(N, r, mod) * mod_cmb(N, (K - A * r) // B, mod)
			ans %= mod
print(ans)

Submission status: Time Limit Exceeded

Solution code:
def main():
    n,a,b,k=map(int,input().split())
    fact=[1]
    mod=998244353
    for i in range(1,n+1):fact.append(fact[-1]*i%mod)
    def inv_n(n):return pow(n,mod-2,mod)
    def nCr(n,r):return inv_n(fact[n-r]*fact[r]%mod)*fact[n]%mod
    ans=0
    ans_list=[]
    for i in range(n+1):
        j=(k-a*i)//b
        if i*a+j*b==k:
            if 0<=j<=n:
                ans_list.append([i,j])
    for p,q in ans_list:
        ans=(ans+nCr(n,p)*nCr(n,q))%mod
    print(ans)
main()

Submission status: Time Limit Exceeded

Solution code:
N, A, B, K = map(int, input().split())
mod = 998244353

fac = [1]
inv = [1]
for i in range(1, N + 1) :
    fac.append(fac[-1] * i % mod)
    inv.append(pow(fac[-1], mod - 2, mod))

ret = 0
for na in range(N + 1) :
    if (K - na * A) % B != 0 :
        continue
        
    nb = (K - na * A) // B
    for ng in range(max(0, na + nb - N), min(na, nb) + 1) :
        ret += fac[N] * inv[na-ng] * inv[nb-ng] * inv[ng] * inv[N-na-nb+ng] % mod
        ret %= mod
        
print(ret)

Submission status: Time Limit Exceeded

Solution code:
N, A, B, K = map(int, input().split())
mod = 998244353

fac = [1]
inv = [1]
for i in range(1, N + 1) :
    fac.append(fac[-1] * i % mod)
    inv.append(pow(fac[-1], mod - 2, mod))

ret = 0
for na in range(N + 1) :
    if (K - na * A) % B != 0 :
        continue
        
    nb = (K - na * A) // B
    for ng in range(min(na, nb) + 1) :
        if not 0 <= na + nb - ng <= N :
            continue
        ret += fac[N] * inv[na-ng] * inv[nb-ng] * inv[ng] * inv[N-na-nb+ng] % mod
        ret %= mod
        
print(ret)

Submission status: Time Limit Exceeded

Solution code:
from heapq import heappush, heappop
from collections import deque,defaultdict,Counter
import itertools
from itertools import permutations,combinations
import sys
import bisect
import string
#import math
#import time
#import random  # randome is not available at Codeforces
def I():
    return int(input())
def MI():
    return map(int,input().split())
def LI():
    return [int(i) for i in input().split()]
def LI_():
    return [int(i)-1 for i in input().split()]
def StoI():
    return [ord(i)-97 for i in input()]
def show(*inp,end='\n'):
    if show_flg:
        print(*inp,end=end)
YN=['Yes','No']
mo=10**9+7
inf=float('inf')
#ts=time.time()
#sys.setrecursionlimit(10**6)
input=lambda: sys.stdin.readline().rstrip()

import sys
sys.setrecursionlimit(10**7)
mo=998244353


n,a,b,k=LI()


f=[0]*(2+n)
r=[0]*(2+n)

def fact(n):
    if n==0:
        f[0]=1
        return 1
    if f[n]!=0:
        return f[n]
    f[n]=n*fact(n-1)%mo
    return f[n]

r[n]=pow(fact(n),mo-2,mo)

def revfact(n):
    if r[n]!=0:
        return r[n]
    r[n]=( (n+1)*revfact(n+1) )%mo
    return r[n]

def comb(n,k):
    return fact(n)*revfact(n-k)*revfact(k)%mo


fact(n)
revfact(0)

show_flg=False
show_flg=True

if a<b:
    a,b=b,a
ans=0
for i in range(min(n+1,k//a+1)):
    j=(k-a*i)//b
    if (k-a*i)%b!=0 or j<0 or j>n:
        continue
    ans+=comb(n,i)*comb(n,j)
    ans%=mo

print(ans%mo)

Submission status: Time Limit Exceeded

Solution code:
from heapq import heappush, heappop
from collections import deque,defaultdict,Counter
import itertools
from itertools import permutations,combinations
import sys
import bisect
import string
#import math
#import time
#import random  # randome is not available at Codeforces
def I():
    return int(input())
def MI():
    return map(int,input().split())
def LI():
    return [int(i) for i in input().split()]
def LI_():
    return [int(i)-1 for i in input().split()]
def StoI():
    return [ord(i)-97 for i in input()]
def show(*inp,end='\n'):
    if show_flg:
        print(*inp,end=end)
YN=['Yes','No']
mo=10**9+7
inf=float('inf')
#ts=time.time()
#sys.setrecursionlimit(10**6)
input=lambda: sys.stdin.readline().rstrip()

import sys
sys.setrecursionlimit(10**7)
mo=998244353


n,a,b,k=LI()


f=[0]*(2+n)
r=[0]*(2+n)

def fact(n):
    if n==0:
        f[0]=1
        return 1
    if f[n]!=0:
        return f[n]
    f[n]=n*fact(n-1)%mo
    return f[n]

r[n]=pow(fact(n),mo-2,mo)

def revfact(n):
    if r[n]!=0:
        return r[n]
    r[n]=( (n+1)*revfact(n+1) )%mo
    return r[n]

def comb(n,k):
    return fact(n)*revfact(n-k)*revfact(k)%mo


fact(n)
revfact(0)

show_flg=False
show_flg=True

if a<b:
    a,b=b,a
ans=0
for i in range(min(n+1,k//a+1)):
    j=(k-a*i)//b
    if (k-a*i)%b!=0 or j<0 or j>n:
        continue
    try:
        ans+=comb(n,i)*comb(n,j)
    except:
        0
    ans%=mo

print(ans%mo)

Submission status: Time Limit Exceeded

Solution code:
from fractions import gcd
mod = 998244353
n,a,b,k = map(int, input().split())
if k % gcd(a,b) != 0:
    print(0)
    exit()
fact = [1]
for i in range(n+10):
    fact.append(fact[-1]*(i+1)%mod)
aaa = fact[n]
for i,j in enumerate(fact):
    fact[i] = pow(j, mod-2, mod)

ans = 0
for i in range(n+1):
    tmp = k-a*i
    if tmp % b:
        continue
    j = tmp//b
    for l in range(max(0, (i+j)-n), min(i,j)+1):
        #print(f"red {i-l}, green {l}, blue {j-l}")
        ans += fact[i-l]*fact[l]*fact[j-l]*fact[n+l-(i+j)]
        ans %= mod
ans = ans*aaa%mod
print(ans)

Submission status: Time Limit Exceeded

Solution code:

import sys
def input():
	return sys.stdin.readline().strip()

N, A, B, K = list(map(int, input().split()))

mod = 998244353

fact_list = [1]
for i in range(1, N + 1):
	fact_list.append((fact_list[-1]*i) % mod)

def pow(x, y, mod=1000000007):
	pow_list = [x]
	i = 1
	while 2**i <= y:
		a = pow_list[-1]**2
		if mod != 0:
			a = a % mod
		pow_list.append(a)
		i += 1
	ans = 1
	for bit in range(len(pow_list)):
		if (2**bit) & y != 0:
			ans *= pow_list[bit]
			if mod != 0:
				ans = ans % mod
	return ans

def fact(n, mod=1000000007):
	return fact_list[n]

def mod_rev(x, mod):
	"""
	関数powが必要
	"""
	return pow(x, mod - 2, mod)


def comb(a, b, mod=1000000007):
	"""
	関数mod_rev, fact, powが必要
	"""
	if a < b or b < 0:
		return 0
	a_fact = fact(a, mod)
	b_fact = fact(b, mod)
	a_b_fact = fact(a - b, mod)
	if mod != 0:
		return (a_fact * mod_rev(b_fact, mod) * mod_rev(a_b_fact, mod))%mod
	else:
		return a_fact//(b_fact*a_b_fact)

ans = 0
for r in range(N + 1):
	rest = K - r * A
	if rest % B == 0 and rest // B >= 0 and rest // B <= N:
		b = rest // B
		ans += comb(N, r, mod)*comb(N, b, mod)
		ans %= mod
print(ans)

Submission status: Time Limit Exceeded

Solution code:
import bisect
import heapq
import itertools
import math
import operator
import os
import re
import string
import sys
from collections import Counter, deque, defaultdict
from copy import deepcopy
from decimal import Decimal
from fractions import gcd
from functools import lru_cache, reduce
from operator import itemgetter, mul, add, xor

import numpy as np
from scipy.misc import comb

if os.getenv("LOCAL"):
    sys.stdin = open("_in.txt", "r")

sys.setrecursionlimit(2147483647)
INF = float("inf")
IINF = 10 ** 18
MOD = 998244353


def get_factorials(max, mod=None):
    """
    階乗 0!, 1!, 2!, ..., max!
    :param int max:
    :param int mod:
    :return:
    """
    ret = [1]
    n = 1
    if mod:
        for i in range(1, max + 1):
            n *= i
            n %= mod
            ret.append(n)
    else:
        for i in range(1, max + 1):
            n *= i
            ret.append(n)
    return ret


def mod_invs(max, mod):
    """
    逆元のリスト 0 から max まで
    :param int max:
    :param int mod:
    """
    invs = [1] * (max + 1)
    for x in range(2, max + 1):
        invs[x] = (-(mod // x) * invs[mod % x]) % mod
    return invs


def factorial_invs(max, mod):
    """
    階乗 0!, 1!, 2!, ..., max! の逆元
    :param int max:
    :param int mod:
    """
    ret = []
    r = 1
    for inv in mod_invs(max, mod):
        r = r * inv % mod
        ret.append(r)
    return ret


class Combination:
    def __init__(self, max, mod):
        """
        :param int max:
        :param int mod: 3 以上の素数であること
        """
        self._factorials = get_factorials(max, mod)
        self._finvs = factorial_invs(max, mod)
        self._mod = mod

    def ncr(self, n, r):
        """
        :param int n:
        :param int r:
        :rtype: int
        """
        if n < r:
            return 0
        return self._factorials[n] * self._finvs[r] % self._mod * self._finvs[n - r] % self._mod


N, A, B, K = list(map(int, sys.stdin.readline().split()))
comb = Combination(max=N, mod=MOD)
ans = 0
# A の数が決まれば B の数も決まる
for a in range(N + 1):
    if (K - a * A) % B != 0:
        continue
    b = int((K - a * A) // B)
    if not (0 <= a <= N and 0 <= b <= N):
        continue

    s = 0
    # 緑
    c = min(a, b)
    # A
    a -= c
    # B
    b -= c
    # 無色
    d = N - a - b - c
    # ここ高速化したい
    while c >= 0 and d >= 0:
        s += comb.ncr(N, a) * comb.ncr(N - a, b) * comb.ncr(N - a - b, c)
        a += 1
        b += 1
        c -= 1
        d -= 1

    ans += s
    ans %= MOD
print(ans)

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(200000)
input = sys.stdin.readline
def ii(): return int(input())
def mi(): return map(int, input().rstrip().split())
def lmi(): return list(map(int, input().rstrip().split()))
def li(): return list(input().rstrip())
# template


# BEGIN CUT HERE
# MOD = 10**9 + 7
MOD = 998244353  # AGC025_B


class Modint():
    '''
    自動でMODで割った余りを計算してくれる整数。MODは素数である必要があり，デフォルトは10**9+7。
    Parameters
    ----------
    n (int): Modintの初期値
    MOD=10**9+7 (int): 余りを計算するMOD。素数である必要がある。
    '''

    def __init__(self, n, mod=MOD):
        if n >= 0:
            self.n = n % mod
        else:
            self.n = (mod - (-n) % mod) % mod
        self.mod = mod

    def __eq__(self, other):
        return self.n == int(other)

    def __ne__(self, other):
        return not self == other

    def __neg__(self):
        return self.__class__(-self.n, self.mod)

    def __str__(self):
        return str(self.n)

    def __int__(self):
        return int(self.n)

    def __iadd__(self, other):
        self.n += int(other)
        self.n %= self.mod
        return self

    def __radd__(self, other):
        self.n += int(other)
        self.n %= self.mod
        return self

    def __isub__(self, other):
        self.n -= int(other)
        self.n %= self.mod
        return self

    def __rsub__(self, other):
        self.n -= int(other)
        self.n %= self.mod
        return self

    def __imul__(self, other):
        self.n = self.n * int(other) % self.mod
        return self

    def __rmul__(self, other):
        self.n = self.n * int(other) % self.mod
        return self

    def inverse(self):
        '''
        フェルマーの小定理を考えると，MOD-2乗することでMODでの逆元を求めることができる。これは組み込み関数のpowを使うと十分に早い（O(log MOD)）。
        '''
        return pow(self.n, self.mod - 2, self.mod)

    def __ifloordiv__(self, other):
        self *= pow(int(other), self.mod - 2, self.mod)
        return self

    def __rfloordiv__(self, other):
        self *= pow(int(other), self.mod - 2, self.mod)
        return self

    def __add__(self, other):
        self += other
        return self

    def __sub__(self, other):
        self -= other
        return self

    def __mul__(self, other):
        self *= other
        return self

    def __floordiv__(self, other):
        self //= other
        return self

    # def comb(self, n: int, k: int):
    #     '''
    #     コンビネーション絡みの定義。comb(n,k):特に前処理をせずnCkを求める
    #     毎回O(N)かかるので死ぬ覚悟でO(N^2)を投げるくらいしか無理

    #     ちなみにですが，これでABC132_D()を出すとPyPy3で1932msくらいですれすれセーフ
    #     '''
    #     if n < k or k < 0:
    #         return Modint(0)
    #     res = Modint(1)
    #     for i in range(int(k)):
    #         res *= Modint(n - i)
    #         res //= Modint(i + 1)
    #     return res

    # def H(self, n: int, k: int):
    #     if n < 0 or k < 0:
    #         return Modint(0)
    #     elif n == 0 and k == 0:
    #         return Modint(1)
    #     else:
    #         return self.comb(n + k - 1, n)


class Combination():
    def __init__(self, sz):
        '''
        Nまでの階乗とその逆元（割り算用）を計算しておく。前処理にO(N)，P, C, Hそれぞれの計算はO(1)。N = 200000なら割と余裕で通る。
        '''
        self._fact = [0] * (sz + 1)
        self._rfact = [0] * (sz + 1)
        self._fact[0] = 1
        self._rfact[sz] = 1
        for i in range(1, sz + 1):
            self._fact[i] = int(self._fact[i - 1] * Modint(i))
        self._rfact[sz] = Modint(self._fact[sz]).inverse()
        for i in range(sz - 1, -1, -1):
            self._rfact[i] = int(self._rfact[i + 1] * Modint(i + 1))

    def fact(self, k: int) -> int:
        return self._fact[k]

    def rfact(self, k: int) -> int:
        return self._rfact[k]

    def P(self, n: int, k: int) -> Modint:
        '''
        nPkの値を返す。nはあらかじめ前処理されたN以下でないとダメ
        Parameters
        ----------
        n (int): nPkのn (0<=n<=N)
        k (int): nPkのk （0<=k<=n）
        Returns
        ----------
        Modint: nPkをModint型で返す。Modintに依存。
        '''
        if k < 0 or n < k:
            return 0
        return Modint(self._fact[n] * self._rfact[n - k])

    def C(self, n: int, k: int) -> Modint:
        '''
        nCkの値を返す。nはあらかじめ前処理されたN以下でないとダメ
        Parameters
        ----------
        n (int): nCkのn(0<=n<=N)
        k (int): nCkのk（0<=k<=n）
        Returns
        ----------
        Modint: nCkをModint型で返す。Modintに依存。
        '''
        if k < 0 or n < k:
            return 0
        return Modint(self._fact[n] * self._rfact[k] * self._rfact[n - k])

    def H(self, n: int, k: int) -> Modint:
        '''
        nHkの値を返す。nはあらかじめ前処理されたN以下でないとダメ

        ちなみにnHkはn個の区別できないものをk個の箱に分けるパターンの数で，結局n+k-1Cnになる。
        Parameters
        ----------
        n (int): nHkのn(0<=n<=N)
        k (int): nHkのk（0<=k<=n）
        Returns
        ----------
        Modint: nHkをModint型で返す。Modintに依存。
        '''
        if n < 0 or k < 0:
            return 0
        elif k == 0:
            return 1
        return self.C(n + k - 1, n)

# END CUT HERE


def ABC132_D():
    N, K = mi()
    res = Combination(N)
    for i in range(1, K + 1):
        print(res.C(K - 1, i - 1) * res.H(N - K - i + 1, i + 1))
# verified on 2019/07/01
# https://atcoder.jp/contests/abc132/tasks/abc132_d
# Python3: 32ms https://atcoder.jp/contests/abc132/submissions/6200580
# PyPy3だとオーバヘッドが大きいのか240msくらいかかるけど，基本はPyPyで良いと思う。


def AGC025_B():
    N, A, B, K = mi()
    res = Combination(N)
    ans = Modint(0)
    for a in range(min(K // A + 1, N + 1)):
        b = (K - a * A) // B
        if A * a + B * b == K and a >= 0 and b >= 0:
            ans += res.C(N, a) * res.C(N, b)
    print(ans)
# verified on 2019/07/01
# https://atcoder.jp/contests/agc025/tasks/agc025_b
# PyPy3: https://atcoder.jp/contests/agc025/submissions/6200598
# Python3だとTLE


if __name__ == '__main__':
    # ABC132_D()
    AGC025_B()

Submission status: Time Limit Exceeded

Solution code:
import sys
sys.setrecursionlimit(200000)
input = sys.stdin.readline
def ii(): return int(input())
def mi(): return map(int, input().rstrip().split())
def lmi(): return list(map(int, input().rstrip().split()))
def li(): return list(input().rstrip())
# template


# BEGIN CUT HERE
# MOD = 10**9 + 7
MOD = 998244353 # AGC025_B


class Modint():
    '''
    自動でMODで割った余りを計算してくれる整数。MODは素数である必要があり，デフォルトは10**9+7。
    Parameters
    ----------
    n (int): Modintの初期値
    MOD=10**9+7 (int): 余りを計算するMOD。素数である必要がある。
    '''

    def __init__(self, n, mod=MOD):
        if n >= 0:
            self.n = n % mod
        else:
            self.n = (mod - (-n) % mod) % mod
        self.mod = mod

    def __eq__(self, other):
        return self.n == int(other)

    def __ne__(self, other):
        return not self == other

    def __neg__(self):
        return self.__class__(-self.n, self.mod)

    def __str__(self):
        return str(self.n)

    def __int__(self):
        return int(self.n)

    def __iadd__(self, other):
        self.n += int(other)
        self.n %= self.mod
        return self

    def __radd__(self, other):
        self.n += int(other)
        self.n %= self.mod
        return self

    def __isub__(self, other):
        self.n -= int(other)
        self.n %= self.mod
        return self

    def __rsub__(self, other):
        self.n -= int(other)
        self.n %= self.mod
        return self

    def __imul__(self, other):
        self.n = self.n * int(other) % self.mod
        return self

    def __rmul__(self, other):
        self.n = self.n * int(other) % self.mod
        return self

    def inverse(self):
        '''
        フェルマーの小定理を考えると，MOD-2乗することでMODでの逆元を求めることができる。これは組み込み関数のpowを使うと十分に早い（O(log MOD)）。
        '''
        return pow(self.n, self.mod - 2, self.mod)

    def __ifloordiv__(self, other):
        self *= pow(int(other), self.mod - 2, self.mod)
        return self

    def __rfloordiv__(self, other):
        self *= pow(int(other), self.mod - 2, self.mod)
        return self

    def __add__(self, other):
        self += other
        return self

    def __sub__(self, other):
        self -= other
        return self

    def __mul__(self, other):
        self *= other
        return self

    def __floordiv__(self, other):
        self //= other
        return self

    def comb(self, n: int, k: int):
        '''
        コンビネーション絡みの定義。comb(n,k):特に前処理をせずnCkを求める
        毎回O(N)かかるので死ぬ覚悟でO(N^2)を投げるくらいしか無理

        ちなみにですが，これでABC132_D()を出すとPyPy3で1932msくらいですれすれセーフ
        '''
        if n < k or k < 0:
            return Modint(0)
        res = Modint(1)
        for i in range(int(k)):
            res *= Modint(n - i)
            res //= Modint(i + 1)
        return res

    def H(self, n: int, k: int):
        if n < 0 or k < 0:
            return Modint(0)
        elif n == 0 and k == 0:
            return Modint(1)
        else:
            return self.comb(n + k - 1, n)


class Combination():
    def __init__(self, sz):
        '''
        前処理にO(N)，それぞれの計算はO(1)。N = 200000なら割と余裕で通る。
        '''
        self._fact = [0] * (sz + 1)
        self._rfact = [0] * (sz + 1)
        self._fact[0] = 1
        self._rfact[sz] = 1
        for i in range(1, sz + 1):
            self._fact[i] = int(self._fact[i - 1] * Modint(i))
        self._rfact[sz] = Modint(self._fact[sz]).inverse()
        for i in range(sz - 1, -1, -1):
            self._rfact[i] = int(self._rfact[i + 1] * Modint(i + 1))

    def fact(self, k: int) -> int:
        return self._fact[k]

    def rfact(self, k: int) -> int:
        return self._rfact[k]

    def P(self, n: int, k: int) -> Modint:
        '''
        nPkの値を返す。nはあらかじめ前処理されたN以下でないとダメ
        Parameters
        ----------
        n (int): nPkのn(0<=n<=N)
        k (int): nPkのk（0<=k<=n）
        Returns
        ----------
        Modint: nPkをModint型で返す。Modintに依存。
        '''
        if k < 0 or n < k:
            return 0
        return Modint(self._fact[n] * self._rfact[n - k])

    def C(self, n: int, k: int) -> Modint:
        '''
        nCkの値を返す。nはあらかじめ前処理されたN以下でないとダメ
        Parameters
        ----------
        n (int): nCkのn(0<=n<=N)
        k (int): nCkのk（0<=k<=n）
        Returns
        ----------
        Modint: nCkをModint型で返す。Modintに依存。
        '''
        if k < 0 or n < k:
            return 0
        return Modint(self._fact[n] * self._rfact[k] * self._rfact[n - k])

    def H(self, n: int, k: int) -> Modint:
        '''
        nHkの値を返す。nはあらかじめ前処理されたN以下でないとダメ

        ちなみにnHkはn個の区別できないものをk個の箱に分けるパターンの数で，結局n+k-1Cnになる。
        Parameters
        ----------
        n (int): nHkのn(0<=n<=N)
        k (int): nHkのk（0<=k<=n）
        Returns
        ----------
        Modint: nHkをModint型で返す。Modintに依存。
        '''
        if n < 0 or k < 0:
            return 0
        elif k == 0:
            return 1
        return self.C(n + k - 1, n)

# END CUT HERE


def ABC132_D():
    N, K = mi()
    res = Combination(N)
    for i in range(1, K + 1):
        print(res.C(K - 1, i - 1) * res.H(N - K - i + 1, i + 1))
# verified on 2019/07/01
# https://atcoder.jp/contests/abc132/tasks/abc132_d
# Python3: 32ms https://atcoder.jp/contests/abc132/submissions/6200580


def AGC025_B():
    N, A, B, K = mi()
    res = Combination(N)
    ans = Modint(0)
    for a in range(K // A + 1):
        b = (K - a * A) // B
        if A * a + B * b == K and a >= 0 and b >= 0:
            ans += res.C(N, a) * res.C(N, b)
    print(ans)
# verified on 2019/07/01
# https://atcoder.jp/contests/agc025/tasks/agc025_b
# Python3: 


if __name__ == '__main__':
    # ABC132_D()
    AGC025_B()

Submission status: Time Limit Exceeded

Solution code:
class Combination:
    '''
    計算量：階乗・逆元テーブルの作成O(N)
            nCkを求めるO(1)
    '''

    def __init__(self, n, MOD):
        self.fact = [1]
        for i in range(1, n + 1):
            self.fact.append(self.fact[-1] * i % MOD)
        self.inv_fact = [pow(self.fact[i] ,MOD - 2 ,MOD) for i in range(n + 1)]
        self.MOD = MOD

    def factorial(self, k):
        '''k!を求める'''
        return self.fact[k]

    def inverse_factorial(self, k):
        '''k!の逆元を求める'''
        return self.inv_fact[k]

    def combination(self, k, r):
        '''kCrを求める'''
        return (self.fact[k] * self.inv_fact[k - r] * self.inv_fact[r]) % self.MOD


n, a, b, k = map(int, input().split())
MOD = 998244353
comb = Combination(n, MOD)
ans = 0
for i in range(n+1):
    if not(k - a*i >= 0 and (k - a*i) % b == 0 and (k - a*i) // b <= n):
        continue
    else:
        ai = i
        bi = (k - a*i) // b
        ans += comb.combination(n, ai) * comb.combination(n, bi)
        ans %= MOD
print(ans)

Submission status: Time Limit Exceeded

Solution code:
MOD = 998244353
n, a, b, k = [int(item) for item in input().split()]

fac = [1] + [0] * n
fac_inv = [1] + [0] * n
for i in range(1, n+1):
    fac[i] = fac[i-1] * (i) % MOD
    fac_inv[i] = fac_inv[i-1] * pow(i, MOD-2, MOD) % MOD

def mod_nCr(n, r):
    if n == 0 and r == 0:
        return 1
    if n < r or n < 0:
        return 0
    tmp = fac_inv[n-r] * fac_inv[r] % MOD
    return tmp * fac[n] % MOD 

if a < b:
    a, b = b, a
max_a_num = k // a + 1
ans = 0
for a_num in range(max_a_num):
    lest = k - (a_num * a)
    if lest % b != 0 or lest < 0:
        continue
    b_num = lest // b
    ans += mod_nCr(n, a_num) * mod_nCr(n, b_num)
    ans %= MOD
print(ans)

Submission status: Time Limit Exceeded

Solution code:
MOD = 998244353
N = 3 * 10**5 + 1

fac = [1] + [0] * N
fac_inv = [1] + [0] * N
for i in range(1, N+1):
    fac[i] = fac[i-1] * (i) % MOD
    fac_inv[i] = fac_inv[i-1] * pow(i, MOD-2, MOD) % MOD

def mod_nCr(n, r):
    if n == 0 and r == 0:
        return 1
    if n < r or n < 0:
        return 0
    tmp = fac_inv[n-r] * fac_inv[r] % MOD
    return tmp * fac[n] % MOD 

n, a, b, k = [int(item) for item in input().split()]
if a < b:
    a, b = b, a
max_a_num = k // a + 1
ans = 0
for a_num in range(max_a_num):
    lest = k - (a_num * a)
    if lest % b != 0 or lest < 0:
        continue
    b_num = lest // b
    ans += mod_nCr(n, a_num) * mod_nCr(n, b_num)
    ans %= MOD
print(ans)