CodeEff/ECCO huggingface dataset:
# Original solution
def find_dex(list,dex):
    for j in range(len(list)):
        if list[j][0] == dex:
            return j
    return 0
n = int(eval(input()))
d = []
left = []
right = []
for i in range(n):
    x,l = list(map(int, input().split()))
    # num , left , right
    left.append([i,x-l+1,x+l-1])
    right.append([i,x-l+1,x+l-1])

left.sort(key=lambda x:x[1],reverse=False)
right.sort(key=lambda x:x[2],reverse=False)

flag = True
p = 10**9 + 1
ans = 0
while len(left) > 0:
    if flag:
        i,l,r = left.pop(-1)
        right.pop(find_dex(right,i))
        flag = False
        if r >= p:
            ans += 1
        p = l

    else:
        i,l,r = right.pop(-1)
        left.pop(find_dex(left,i))
        flag = True
        if r >= p:
            ans += 1
        p = l

    #print(i,l,r)
    #print(left)
    #print(right)

print((n-ans))


# Optimized solution
n = int(eval(input()))
d = []
left = []
right = []
for i in range(n):
    x,l = list(map(int, input().split()))
    # num , left , right
    d.append([x-l,x+l])

d.sort()
p = d[0][1]
ans = n
for i in range(1,n):
    if d[i][0] < p:
        ans -= 1
        p = min(p,d[i][1])
    else:
        p = d[i][1]
print(ans)
# Original solution
import sys
from operator import itemgetter

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    LR = [None] * N
    for i in range(N):
        X, L = list(map(int, input().split()))
        LR[i] = (X - L, X + L)

    LR.sort(key=itemgetter(0))
    ans = N
    cur_R = LR[0][1]
    for L, R in LR[1:]:
        if L < cur_R:
            ans -= 1
            cur_R = min(cur_R, R)
        else:
            cur_R = R

    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
import sys
from operator import itemgetter

input = sys.stdin.readline


def main():
    N = int(eval(input()))
    LR = [None] * N
    for i in range(N):
        X, L = list(map(int, input().split()))
        LR[i] = (X - L, X + L)

    LR.sort(key=itemgetter(0))
    ans = N
    cur_R = LR[0][1]
    for L, R in LR[1:]:
        if L < cur_R:
            ans -= 1
            if R < cur_R:
                cur_R = R
        else:
            cur_R = R

    print(ans)


if __name__ == "__main__":
    main()
# Original solution
N = int(eval(input()))
ts=[]
for i in range(N):
  x, l = list(map(int,input().split()))
  s = max(x-l,0)
  t = min(10**9,x+l)
  ts.append([t,s])
ts.sort()

count = 0
lastT = 0
for i in ts:
  if i[1]>=lastT:
    count+=1
    lastT=i[0]
print(count)

# Optimized solution
N = int(eval(input()))
st = []
for i in range(N):
  x,l=list(map(int,input().split()))
  s = max(x-l,0)
  t = min(x+l,10**9)
  st.append([t,s])
st.sort()

count = 0
lastT=0
for i in range(N):
  if st[i][1]>=lastT:
    count+=1
    lastT = st[i][0]
    
print(count)
# Original solution
n=int(eval(input()))
l=sorted([list(map(int,input().split())) for _ in range(n)])
c=0
x=[0]*n

def d_min(a,b):
    return a-b
def d_max(a,b):
    return a+b

for i in range(n-1):
    if x[i] != 0:
        continue
    for k in range(1,n-i):
        if d_max(*l[i]) > d_min(*l[i+k]):
            c+=1
            x[i+1]+=1
print((n-c))

# Optimized solution
n=int(eval(input()))
r=[]
cnt=1

for _ in range(n):
    x,l=list(map(int,input().split()))
    s=x-l
    t=x+l
    r.append([s,t])
    
r=sorted(r,key=lambda x: x[1])
t0=r[0][1]

for s,t in r[1:]:
    if t0<=s:
        cnt+=1
        t0=t

print(cnt)
# Original solution
import sys
from operator import itemgetter

read = sys.stdin.read

N, *XL = list(map(int, read().split()))
seq = []

for X, L in zip(*[iter(XL)] * 2):
    seq.append((X - L, X + L))

seq.sort(key=itemgetter(1))
answer = 0
left = -10 ** 10
for i, j in seq:
    if left <= i:
        answer += 1
        left = j

print(answer)

# Optimized solution
import sys
from operator import itemgetter

read = sys.stdin.read

N, *XL = list(map(int, read().split()))

seq = [(X - L, X + L) for X, L in zip(*[iter(XL)] * 2)]
seq.sort(key=itemgetter(1))
answer = 0
left = -10 ** 10
for i, j in seq:
    if left <= i:
        answer += 1
        left = j

print(answer)
# Original solution
#!/usr/bin/env python3
import sys
INF = float("inf")


def solve(N: int, X: "List[int]", L: "List[int]"):

    # 区間に変換する
    segs = [(x-l, x+l) for x, l in zip(X, L)]
    segs.sort(key=lambda x: x[1])  # 尻でソート

    # DP i個目の区間まで考えた時の残せる数
    DP = [0]*N
    DP[0] = 1
    for i in range(1, N):
        # 重なっていなければ
        if segs[i-1][1] <= segs[i][0]:
            DP[i] = DP[i-1]+1
        else:
            # 加えないか
            DP[i] = DP[i-1]
            # 重なるものを抜いた場合の個数+1
            left = -1
            right = i-1
            while right-left > 1:
                mid = (right+left)//2
                if segs[mid][1] <= segs[i][0]:
                    left = mid
                else:
                    right = mid
            # すべて重なるケースは区別
            if left == -1:
                buf = 1
            else:
                buf = DP[left]+1
            DP[i] = max(buf, DP[i-1])
    print((DP[-1]))

    return


def main():

    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    X = [int()] * (N)  # type: "List[int]"
    L = [int()] * (N)  # type: "List[int]"
    for i in range(N):
        X[i] = int(next(tokens))
        L[i] = int(next(tokens))
    solve(N, X, L)


if __name__ == '__main__':
    main()


# Optimized solution
#!/usr/bin/env python3
import sys
INF = float("inf")


def solve(N: int, X: "List[int]", L: "List[int]"):

    # 区間に変換する
    segs = [(x-l, x+l) for x, l in zip(X, L)]
    segs.sort(key=lambda x: x[1])  # 尻でソート

    last = -INF
    count = 0
    for i in range(N):
        if last <= segs[i][0]:
            last = segs[i][1]
            count += 1
    print(count)

    return


def main():

    def iterate_tokens():
        for line in sys.stdin:
            for word in line.split():
                yield word
    tokens = iterate_tokens()
    N = int(next(tokens))  # type: int
    X = [int()] * (N)  # type: "List[int]"
    L = [int()] * (N)  # type: "List[int]"
    for i in range(N):
        X[i] = int(next(tokens))
        L[i] = int(next(tokens))
    solve(N, X, L)


if __name__ == '__main__':
    main()
# Original solution
N = int(eval(input()))
arr = [list(map(int,input().split())) for i in range(N)]
arr = sorted(arr)
F = [True]*N
P = [0]*N
for i in range(N):
  P[i] = [arr[i][0]-arr[i][1], arr[i][0]+arr[i][1]]
for i in range(N):
  for j in range(i+1,N):
    if F[i]:
      if P[i][1] > P[j][0]:
        F[j] = False
      else:
        break
print((F.count(True)))


# Optimized solution
N = int(eval(input()))
arr = [list(map(int,input().split())) for i in range(N)]
arr = sorted(arr, key=lambda x: x[0])
F = [True]*N
P = [0]*N
for i in range(N):
  P[i] = [arr[i][0]-arr[i][1], arr[i][0]+arr[i][1]]
P = sorted(P,key=lambda x:x[1])
ind = 0
for i in range(1,N):
  if P[i][0] < P[ind][1]:
    F[i] = False
  else:
    ind = i
print((F.count(True)))
# Original solution
def main():
    N = int(eval(input()))
    X = []
    L = []
    for i in range(N):
        x, l = [int(s) for s in input().split()]
        X.append(x)
        L.append(l)

    ranges = []
    for i in range(N):
        ranges.append((X[i] - L[i], X[i] + L[i]))
    ranges.sort(key=lambda x: x[0])

    while True:
        dup = [0 for i in range(len(ranges))]
        for i in range(len(ranges) - 1):
            if ranges[i][1] > ranges[i + 1][0]:
                dup[i] += 1
                dup[i + 1] += 1

        remove_index = [(i, dup[i]) for i in range(len(dup)) if dup[i] > 0]
        if len(remove_index) == 0:
            break
        remove_index.sort(key=lambda x: x[1], reverse=True)
        ranges.pop(remove_index[0][0])
    print((len(ranges)))


if __name__ == "__main__":
    main()


# Optimized solution
def main():
    N = int(eval(input()))
    X = []
    L = []
    for i in range(N):
        x, l = [int(s) for s in input().split()]
        X.append(x)
        L.append(l)

    ranges = []
    for i in range(N):
        ranges.append((X[i] - L[i], X[i] + L[i]))
    ranges.sort(key=lambda x: x[1])

    cnt = len(ranges)
    end = ranges[0][1]
    for i in range(1, len(ranges)):
        if ranges[i][0] < end:
            cnt -= 1
        else:
            end = ranges[i][1]
    print(cnt)


if __name__ == "__main__":
    main()
# Original solution
n=int(eval(input()))
s=[]
t=[]
for i in range(n):
    x,l=list(map(int,input().split()))
    s.append(x-l)
    t.append(x+l)
itv = []
for i in range(n):
    itv.append([t[i],s[i]])
itv.sort()

ass=0
tt=-10000000000
for i in range(n):
    if tt<=itv[i][1]:
        ass+=1
        tt=itv[i][0]
print(ass)


# Optimized solution
n=int(eval(input()))
sec=[list(map(int,input().split())) for i in range(n)]
for i in range(n):
    sec[i][0]+=sec[i][1]
    sec[i][1]*=-2
    sec[i][1]+=sec[i][0]
sec.sort()

ans=0
#-inf
t=-10000000000
for i in range(n):
    #=をつけるのを忘れずに
    if t<=sec[i][1]:#スタートがロボットアームのある最大の座標以上でなければならない
        ans+=1#以上なら+1
        t=sec[i][0]#ロボットアームのある最大の座標を更新
print(ans)
# Original solution
N = int(eval(input()))
X = [0]*N
L = [0]*N
XpL = [0]*N
XmL = [0]*N
cnt = 0
for i in range(N):
    X[i], L[i] = list(map(int, input().split()))
    XpL[i] = X[i]+L[i]
    XmL[i] = max(0, X[i]-L[i])
    
    for j in range(i):
        if(XmL[i] < XpL[j] and XmL[j] < XpL[i]):
            cnt += 1
            XpL[i] = XpL[j]
            XmL[i] = XmL[j]
print((N-cnt))

# Optimized solution
import sys
N = int(eval(input()))
a = sorted([(x+l, x-l) for x, l in (list(map(int, l.split())) for l in sys.stdin)])

last = a[0][0]
ans = 1

for r, l in a[1:]:
    if(last <= l):
        ans += 1
        last = r
print(ans)
# Original solution
from functools import lru_cache


def prepare(n, MOD):
    f = 1
    factorials = [1] * (n + 1)
    for m in range(1, n + 1):
        f = f * m % MOD
        factorials[m] = f
    inv = pow(f, MOD - 2, MOD)
    invs = [1] * (n + 1)
    invs[n] = inv
    for m in range(n, 1, -1):
        inv = inv * m % MOD
        invs[m - 1] = inv

    return factorials, invs


def get_nhr(n, facts, invs, MOD):
    @lru_cache(maxsize=None)
    def nhr(r):
        return facts[n + r - 1] * invs[r] * invs[n - 1] % MOD

    return nhr


def solve(n, m):
    MOD = 998244353
    facts, invs = prepare(n + 3 * m, MOD)
    fn = facts[n]
    nhr = get_nhr(n, facts, invs, MOD)
    ans = 0
    for odd in range(m % 2, min(m, n) + 1, 2):
        tmp = nhr((3 * m - odd) // 2)
        if odd > 0:
            tmp -= odd * nhr((m - odd) // 2)
        if odd < n and odd <= m - 2:
            tmp -= (n - odd) * nhr((m - odd - 2) // 2)
        ans = (ans + fn * invs[odd] * invs[n - odd] % MOD * tmp) % MOD
    return ans


n, m = list(map(int, input().split()))
print((solve(n, m)))


# Optimized solution
def prepare(n, MOD):
    f = 1
    factorials = [1] * (n + 1)
    for m in range(1, n + 1):
        f = f * m % MOD
        factorials[m] = f
    inv = pow(f, MOD - 2, MOD)
    invs = [1] * (n + 1)
    invs[n] = inv
    for m in range(n, 1, -1):
        inv = inv * m % MOD
        invs[m - 1] = inv

    return factorials, invs


def get_nhr(n, facts, invs, MOD):
    def nhr(r):
        return facts[n + r - 1] * invs[r] * invs[n - 1] % MOD

    return nhr


def solve(n, m):
    MOD = 998244353
    facts, invs = prepare(n + 3 * m, MOD)
    fn = facts[n]
    nhr = get_nhr(n, facts, invs, MOD)
    nm2 = min(n, m - 1)
    ans = 0
    for odd in range(m % 2, min(m, n) + 1, 2):
        tmp = nhr((3 * m - odd) // 2)
        if odd > 0:
            tmp -= odd * nhr((m - odd) // 2)
        if odd < nm2:
            tmp -= (n - odd) * nhr((m - odd - 2) // 2)
        ans = (ans + fn * invs[odd] * invs[n - odd] % MOD * tmp) % MOD
    return ans


n, m = list(map(int, input().split()))
print((solve(n, m)))
# Original solution
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
from bisect import bisect_left, bisect_right
import random
from itertools import permutations, accumulate, combinations
import sys
import string



INF = float('inf')
def LI(): return list(map(int, sys.stdin.readline().split()))
def I(): return int(sys.stdin.readline())
def LS(): return sys.stdin.readline().split()
def S(): return sys.stdin.readline().strip()
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 998244353


n, m = LI()
total = m * 3


fac = [1] * (total + n)
inv = [1] * (total + n)
i = 1
for j in range(1, total + n):
    i = i * j % mod
    fac[j] = i
    inv[j] = pow(i, mod - 2, mod)



def comb(n, r):
    if r > n:
        return 0
    return fac[n] * inv[n - r] * inv[r] % mod



ans = comb(total + n - 1, n - 1)
for i in range(m + 2, min(n + 1, total + 1)):
    if (total - i) % 2 == 0:
        ans -= comb(n, i) * comb(n + (total - i) // 2 - 1, n - 1) % mod
        ans %= mod


ret = 0
for i in range(m):
    ret = (ret + comb(i + n - 2, n - 2)) % mod


ans -= (ret * n) % mod
print((ans % mod))

# Optimized solution
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
from bisect import bisect_left, bisect_right
import random
from itertools import permutations, accumulate, combinations
import sys
import string



INF = float('inf')
def LI(): return list(map(int, sys.stdin.readline().split()))
def I(): return int(sys.stdin.readline())
def LS(): return sys.stdin.readline().split()
def S(): return sys.stdin.readline().strip()
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 998244353


n, m = LI()
total = m * 3

fac = [1] * (total+n+1)
inv = [1] * (total+n+1)
for i in range(total+n):
    fac[i+1] = fac[i]*(i+1)%mod

inv[total+n]=pow(fac[-1], mod-2, mod)
for j in range(total+n-1, -1, -1):
    inv[j]=inv[j+1]*(j+1)%mod



def comb(n, r):
    if r > n:
        return 0
    return fac[n] * inv[n - r] * inv[r] % mod


ans = comb(total+n-1, n-1)
for i in range(m + 2, min(n + 1, total + 1)):
    if (total - i) % 2 == 0:
        ans -= comb(n, i) * comb(n + (total - i) // 2 - 1, n - 1) % mod
        ans %= mod


ret = 0
for i in range(m):
    ret = (ret + comb(i + n - 2, n - 2)) % mod


ans -= (ret * n) % mod
print((ans % mod))
# Original solution
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
from bisect import bisect_left, bisect_right
import random
from itertools import permutations, accumulate, combinations
import sys
import string



INF = float('inf')
def LI(): return list(map(int, sys.stdin.readline().split()))
def I(): return int(sys.stdin.readline())
def LS(): return sys.stdin.readline().split()
def S(): return sys.stdin.readline().strip()
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 998244353


n, m = LI()
total = m * 3

fac = [1] * (total+n+1)
inv = [1] * (total+n+1)
for i in range(total+n):
    fac[i+1] = fac[i]*(i+1)%mod

inv[total+n]=pow(fac[-1], mod-2, mod)
for j in range(total+n-1, -1, -1):
    inv[j]=inv[j+1]*(j+1)%mod



def comb(n, r):
    if r > n:
        return 0
    return fac[n] * inv[n - r] * inv[r] % mod


ans = comb(total+n-1, n-1)
for i in range(m + 2, min(n + 1, total + 1)):
    if (total - i) % 2 == 0:
        ans -= comb(n, i) * comb(n + (total - i) // 2 - 1, n - 1) % mod
        ans %= mod


ret = 0
for i in range(m):
    ret = (ret + comb(i + n - 2, n - 2)) % mod


ans -= (ret * n) % mod
print((ans % mod))

# Optimized solution
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
import math
import bisect
import random
from itertools import permutations, accumulate, combinations, product
import sys
from pprint import pprint
from copy import deepcopy
import string
from bisect import bisect_left, bisect_right
from math import factorial, ceil, floor
from operator import mul
from functools import reduce
from pprint import pprint


sys.setrecursionlimit(2147483647)
INF = 10 ** 15
def LI(): return list(map(int, sys.stdin.buffer.readline().split()))
def I(): return int(sys.stdin.buffer.readline())
def LS(): return sys.stdin.buffer.readline().rstrip().decode('utf-8').split()
def S(): return sys.stdin.buffer.readline().rstrip().decode('utf-8')
def IR(n): return [I() for i in range(n)]
def LIR(n): return [LI() for i in range(n)]
def SR(n): return [S() for i in range(n)]
def LSR(n): return [LS() for i in range(n)]
def SRL(n): return [list(S()) for i in range(n)]
def MSRL(n): return [[int(j) for j in list(S())] for i in range(n)]
mod = 998244353

n, m = LI()
a = n + 3 * m
fac = [1] * (a + 1)
inv = [1] * (a + 1)
for j in range(1, a + 1):
    fac[j] = fac[j-1] * j % mod

inv[a] = pow(fac[a], mod-2, mod)
for j in range(a-1, -1, -1):
    inv[j] = inv[j+1] * (j+1) % mod

def comb(x, y):
    if y > x or x < 0 or y < 0:
        return 0
    return fac[x] * inv[x - y] * inv[y] % mod

ans = 0
for i in range(min(m + 1, n + 1)):
    if (m - i) % 2:
        continue
    ans += comb(n, i) * comb((m * 3 - i) // 2 + n - 1, n - 1)
    ans %= mod

print(((ans - n * comb(m - 1 + n - 1, n - 1)) % mod))
# Original solution
import sys
input=sys.stdin.readline

N,M=list(map(int,input().split()))
mod=998244353

#階乗テーブル
g1=[1,1]
for i in range(2,3*M//2+N+2):
    g1.append(g1[-1]*i%mod)

def cmb(n,r):
    return g1[n]*pow(g1[r],mod-2,mod)*pow(g1[n-r],mod-2,mod)%mod

#奇数の和で場合分け
#iは奇数の数

ans=0
for i in range(min(N+1,M+1)):
    if M%2!=i%2:
        continue
    m=(3*M-i)//2
    num=(cmb(m+N-1,N-1)-i*cmb(m-M+N-1,N-1))%mod
    if m>=M+1:
        num=(num-(N-i)*cmb(m-M+N-2,N-1))%mod
    ans=(ans+cmb(N,i)*num)%mod

print(ans)   

# Optimized solution
import sys
input=sys.stdin.readline
N,M=list(map(int,input().split()))
mod=998244353

inv=[0]*(3*M//2+N+2)
inv[1]=1
for i in range(2,3*M//2+N+2):
    inv[i]=-(mod//i)*inv[mod%i]%mod

#階乗テーブル
g1=[1,1]
g2=[1,1]
for i in range(2,3*M//2+N+2):
    num_1=g1[-1]*i%mod
    g1.append(num_1)
    g2.append(g2[-1]*inv[i]%mod)
    
def cmb(n,r):
    return g1[n]*g2[r]*g2[n-r]%mod

#奇数の和で場合分け
#iは奇数の数

ans=0
for i in range(min(N+1,M+1)):
    if M%2!=i%2:
        continue
    m=(3*M-i)//2
    num=(cmb(m+N-1,N-1)-i*cmb(m-M+N-1,N-1))%mod
    if m>=M+1:
        num=(num-(N-i)*cmb(m-M+N-2,N-1))%mod
    ans=(ans+cmb(N,i)*num)%mod

print(ans)
# Original solution
o=998244353
r=2500100
f=[1]
for i in range(1,r):f.append(f[-1]*i%o)
def c(n,k):return f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)%o
n,m=list(map(int,input().split()))
w=3*m
a=(c(n+w-1,n-1)-n*c(n+m-2,n-1))%o
if n>m+1:
 for i in range(m+1,min(w,n)+1):
  if w-i&1:continue
  a=(a-c(n,i)*c((w-i)//2+n-1,n-1))%o
print(a)

# Optimized solution
o=998244353
f=[1]
for i in range(1,2500100):f.append(f[-1]*i%o)
def c(n,k):return f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)%o
n,m=list(map(int,input().split()))
w=3*m
u=n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a=(a-c(n,i)*c((w-i)//2+u,u))%o
print((a%o))
# Original solution
o=998244353
f=[1]
for i in range(1,2500100):f.append(f[-1]*i%o)
def c(n,k):return f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w=3*m
u=n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a=(a-c(n,i)*c((w-i)//2+u,u))%o
print((a%o))

# Optimized solution
o=998244353
f=[1]
for i in range(1,2500100):f.append(f[-1]*i%o)
def c(n,k):return f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w=3*m
u=n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a-=c(n,i)*c((w-i)//2+u,u)
print((a%o))
# Original solution
o,f=998244353,[1]
for i in range(1,2500100):f.append(f[-1]*i%o)
def c(n,k):return f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w,u=3*m,n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a-=c(n,i)*c((w-i)//2+u,u)
print((a%o))

# Optimized solution
o,f=998244353,[1]
for i in range(1,2500100):f.append(f[-1]*i%o)
c=lambda n,k:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w,u=3*m,n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a-=c(n,i)*c((w-i)//2+u,u) 
print((a%o))
# Original solution
o,f,i=998244353,[1],1
while i<o/399:f+=[f[-1]*i%o];i+=1
c=lambda n,k:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w,u=3*m,n-1
a=c(w+u,u)-n*c(n+m-2,u)
if u>m:
 for i in range(m+1,min(w,n)+1):
  if w-i+1&1:a-=c(n,i)*c((w-i)//2+u,u) 
print((a%o))

# Optimized solution
o,f,i=998244353,[1],1
while i<o/399:f+=[f[-1]*i%o];i+=1
c=lambda n,k:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()))
w,u,j=3*m,n-1,m+1
a=c(w+u,u)-n*c(n+m-2,u)
if w-j&1:j+=1
while j<=min(w,n):a-=c(n,j)*c((w-j)//2+u,u);j+=2
print((a%o))
# Original solution
o,f,i=998244353,[1],1
while i<o>>8:f+=[f[-1]*i%o];i+=1
c=lambda n,k:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
n,m=list(map(int,input().split()));w,u=3*m,n-1;a=c(w+u,u)-n*c(n+m-2,u)
while-~m<min(w,n):m+=2;a-=c(n,m)*c(2*u+w-m>>1,u)
print((a%o))

# Optimized solution
n,m=list(map(int,input().split()))
w,u=3*m,n-1
o,f,i=998244353,[1],1
while i<w+n:f+=[f[-1]*i%o];i+=1
c=lambda n,k:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
a=c(w+u,u)-n*c(n+m-2,u)
while-~m<min(w,n):m+=2;a-=c(n,m)*c(2*u+w-m>>1,u)
print((a%o))
# Original solution
n,m=list(map(int,input().split()))
w,u=3*m,n-1
o,f,i=998244353,[1],1
while i<w+n:f+=[f[-1]*i%o];i+=1
c=lambda n,k=u:f[n]*pow(f[n-k],o-2,o)*pow(f[k],o-2,o)
a=c(w+u)-n*c(n+m-2)
while~-n>m<w:m+=2;a-=c(n,m)*c(2*u+w-m>>1)
print((a%o))

# Optimized solution
n,m=list(map(int,input().split()))
o,f,i=998244353,[1],1
while i<3*m+n:f+=[f[-1]*i%o];i+=1
c=lambda x,y=n-1:f[x]*pow(f[x-y]*f[y]%o,o-2,o)
a=c(-1)-n*c(n+m-2)
while~-n>m<i-n:m+=2;a-=c(n,m)*c(n-1+i-m>>1)
print((a%o))