//#define DEBUG
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace __gnu_pbds; 
using namespace std;
 
#define BSET(a, p) ((a) | (1ll << (p)))
#define BCHK(a, p) ((a) & (1ll << (p)))
#define BXOR(a, p) ((a) ^ (1ll << (p)));
#define BREM(a, p) (BCHK(a, p)?(BXOR(a, p)):(a))
#define BSHO(a, N) (bitset<N>(a))
 
#define fi first
#define sc second 
#define pb push_back
 
 
#ifdef DEBUG
    #define dbg(s) {s;}
    #define PRELUDE
#endif
 
#ifndef DEBUG 
    #define PRELUDE { ios :: sync_with_stdio(false); cin.tie(0); cout.tie(0); }
    #define dbg(s)
    #define endl "\n"
#endif
 
using namespace std;
 
 
#define int ll
#define i32 int32_t
 
#define RBTTYPE int
#define ordered_set tree<RBTTYPE, null_type, less<RBTTYPE>, rb_tree_tag,tree_order_statistics_node_update> 
 
#define all(v) (v).begin(),(v).end()
 
typedef long long ll;
typedef long double ld;
typedef pair< int, int > pii;
typedef pair< ll, ll > pll;
 
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
inline int ri(int x) { // from [0, n-1]
    return uniform_int_distribution<int>(0, x - 1)(rng);
}
 
inline ld rf() { // from [0, 1]
    return uniform_real_distribution<ld>(0, 1)(rng);
}
 
ll gcd(ll x, ll y) {
    if (x < y) return gcd(y, x);
    if (y == 0) return x;
    return gcd(y, x % y);
} 
 
const ll inf = 1e9 + 7;
const ll mod = 998244353ll;
 
ll modexp(ll x, ll ex) {
    ll ans = 1ll;
    while (ex > 0) {
        if (ex & 1ll) ans = (ans * x) % mod;
        ex >>= 1ll;
        x = (x * x) % mod;
    }
    return ans;
}
  
const int maxn = 3e6 + 7;


int fac[maxn];
int faci[maxn];

int C(int n, int m) {
    if (m > n) return 0;
    if (m < 0) return 0;
    int ans = (fac[n] * faci[m]) % mod;
    ans = (ans * faci[n - m]) % mod;
    return ans;
}


i32 main() {
    //freopen("<file>.in", "r", stdin);
    //freopen("<file>.out", "w", stdout);

    PRELUDE;
   
    fac[0] = 1ll; faci[0] = 1ll;
    for (int j = 1; j < maxn; j++) {
        fac[j] = (j * 1ll * fac[j - 1]) % mod;
        faci[j] = modexp(fac[j], mod - 2);
    }

    int n, m; cin >> n >> m;

    int total = C(n - 1 + m + m + m, n - 1);
    //cout << total << endl;

    int part1 = 0;
    for (int j = m + m + 1; j <= m + m + m; j++) {
        int cur = n * C(m + m + m - j + n - 2, n - 2);
     ////   cout << j << " ? " << cur << endl;
        cur %= mod;
        part1 += cur;
    }
    part1 %= mod;
    
    //cout << part1 << endl;

    int part2 = 0;

    for (int k = m + 1; k <= n; k++) {
        
        /*int cur = C(k, m + 1);
        int cur2 = C(n, k);
        int sum = m + m + m - k;
        if (sum % 2) continue;
        int cur3 = C(sum / 2 + n - k - 1, n - k - 1);
        int sg = ((k - m - 1) % 2 == 0) ? 1 : (mod - 1);

        int ans = (((((cur * cur2) % mod) * cur3) % mod) * sg) % mod;
        cout << ans << endl;
        part2 = (part2 + ans) % mod;*/

        int cur = C(n, k);
        int sum = m * 3 - k;
        if (sum % 2) continue;
        sum /= 2;
        int cur2 = C(sum + n - 1, n - 1);
        int ans = (cur * cur2) % mod;
        part2 += ans;

    }

    part2 %= mod;

    //cout << part2 << endl;

    cout << (total + mod - part1 + mod - part2) % mod << endl; 
}





Measured memory_bytes: 47104