#include <functional>
#include <cassert>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <utility>
#include <type_traits>
namespace loquat {
template <typename T>
static std::pair<T, T> extended_gcd(T a, T b){
	if(b == 0){ return std::pair<T, T>(1, 0); }
	const auto p = extended_gcd(b, a % b);
	return std::pair<T, T>(p.second, p.first - a / b * p.second);
}
}
namespace loquat {
template <int MOD>
class modulus_integer {
public:
	typedef modulus_integer<MOD> self_type;
private:
	int m_value;
	static self_type unsafe_construct(int x) noexcept {
		self_type y;
		y.m_value = x;
		return y;
	}
public:
	modulus_integer() noexcept
		: m_value(0)
	{ }
	modulus_integer(int x) noexcept
		: m_value(x % MOD)
	{
		if(m_value < 0){ m_value += MOD; }
	}
	int operator*() const noexcept { return m_value; }
	self_type& operator=(const self_type& x) noexcept {
		m_value = x.m_value;
		return *this;
	}
	self_type operator-(const self_type& x) const noexcept {
		const int y = m_value - x.m_value;
		return unsafe_construct(y < 0 ? y + MOD : y);
	}
	self_type operator*(const self_type& x) const noexcept {
		return unsafe_construct(
			static_cast<long long>(m_value) * x.m_value % MOD);
	}
	self_type operator/(const self_type& x) const {
		return (*this) * self_type(extended_gcd(x.m_value, MOD).first);
	}
	self_type& operator-=(const self_type &x) noexcept {
		return (*this = *this - x);
	}
};
template <int MOD>
inline std::ostream& operator<<(
	std::ostream& os, const modulus_integer<MOD>& x)
{
	os << *x;
	return os;
}
}
namespace loquat {
template <int MOD>
inline modulus_integer<MOD> modulus_factorial(int x){
	using mint = modulus_integer<MOD>;
	static std::vector<mint> table(1, mint(1));
	assert(x >= 0);
	while(static_cast<int>(table.size()) <= x){
		const int t = static_cast<int>(table.size());
		table.push_back(table.back() * mint(t));
	}
	return table[x];
}
template <int MOD>
inline modulus_integer<MOD> modulus_inv_factorial(int x){
	using mint = modulus_integer<MOD>;
	static std::vector<mint> table(1, mint(1));
	assert(x >= 0);
	while(static_cast<int>(table.size()) <= x){
		const int t = static_cast<int>(table.size());
		table.push_back(table.back() / mint(t));
	}
	return table[x];
}
template <int MOD>
inline modulus_integer<MOD> modulus_combination(int n, int k){
	if(k < 0 || n < k){ return 0; }
	const auto a = modulus_factorial<MOD>(n);
	const auto b = modulus_inv_factorial<MOD>(n - k);
	const auto c = modulus_inv_factorial<MOD>(k);
	return a * b * c;
}
template <int MOD>
inline modulus_integer<MOD> modulus_multichoose(int n, int k){
	return modulus_combination<MOD>(n + k - 1, k);
}
}
using namespace std;
static const int MOD = 998244353;
using mint = loquat::modulus_integer<MOD>;
int main(){
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	mint answer = loquat::modulus_multichoose<MOD>(3 * m + 1, n - 1);
	for(int i = 2 * m + 1; i <= 3 * m; ++i){
		answer -= loquat::modulus_multichoose<MOD>(3 * m - i + 1, n - 2) * n;
	}
	for(int i = m + 2; i <= 3 * m && i <= n; i += 2){
		answer -=
			  loquat::modulus_combination<MOD>(n, i)
			* loquat::modulus_multichoose<MOD>((3 * m - i) / 2 + 1, n - 1);
	}
	cout << answer << endl;
	return 0;
}


Measured memory_bytes: 26212