#pragma GCC optimize("O2") #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define int ll #define INT128_MAX (__int128)(((unsigned __int128) 1 << ((sizeof(__int128) * __CHAR_BIT__) - 1)) - 1) #define INT128_MIN (-INT128_MAX - 1) #define clock chrono::steady_clock::now().time_since_epoch().count() #ifdef DEBUG #define dbg(x) cout << (#x) << " = " << x << '\n' #else #define dbg(x) #endif namespace R = std::ranges; namespace V = std::views; using namespace std; using ll = long long; using ull = unsigned long long; using ldb = long double; using pii = pair; using pll = pair; //#define double ldb template ostream& operator<<(ostream& os, const pair pr) { return os << pr.first << ' ' << pr.second; } template ostream& operator<<(ostream& os, const array &arr) { for(const T &X : arr) os << X << ' '; return os; } template ostream& operator<<(ostream& os, const vector &vec) { for(const T &X : vec) os << X << ' '; return os; } template ostream& operator<<(ostream& os, const set &s) { for(const T &x : s) os << x << ' '; return os; } //reference: https://github.com/NyaanNyaan/library/blob/master/modint/montgomery-modint.hpp#L10 //note: mod should be a prime less than 2^30. template struct MontgomeryModInt { using mint = MontgomeryModInt; using i32 = int32_t; using u32 = uint32_t; using u64 = uint64_t; static constexpr u32 get_r() { u32 res = 1, base = mod; for(i32 i = 0; i < 31; i++) res *= base, base *= base; return -res; } static constexpr u32 get_mod() { return mod; } static constexpr u32 n2 = -u64(mod) % mod; //2^64 % mod static constexpr u32 r = get_r(); //-P^{-1} % 2^32 u32 a; static u32 reduce(const u64 &b) { return (b + u64(u32(b) * r) * mod) >> 32; } static u32 transform(const u64 &b) { return reduce(u64(b) * n2); } MontgomeryModInt() : a(0) {} MontgomeryModInt(const int64_t &b) : a(transform(b % mod + mod)) {} mint pow(u64 k) const { mint res(1), base(*this); while(k) { if (k & 1) res *= base; base *= base, k >>= 1; } return res; } mint inverse() const { return (*this).pow(mod - 2); } u32 get() const { u32 res = reduce(a); return res >= mod ? res - mod : res; } mint& operator+=(const mint &b) { if (i32(a += b.a - 2 * mod) < 0) a += 2 * mod; return *this; } mint& operator-=(const mint &b) { if (i32(a -= b.a) < 0) a += 2 * mod; return *this; } mint& operator*=(const mint &b) { a = reduce(u64(a) * b.a); return *this; } mint& operator/=(const mint &b) { a = reduce(u64(a) * b.inverse().a); return *this; } mint operator-() { return mint() - mint(*this); } bool operator==(mint b) const { return (a >= mod ? a - mod : a) == (b.a >= mod ? b.a - mod : b.a); } bool operator!=(mint b) const { return (a >= mod ? a - mod : a) != (b.a >= mod ? b.a - mod : b.a); } friend mint operator+(mint a, mint b) { return a += b; } friend mint operator-(mint a, mint b) { return a -= b; } friend mint operator*(mint a, mint b) { return a *= b; } friend mint operator/(mint a, mint b) { return a /= b; } friend ostream& operator<<(ostream& os, const mint& b) { return os << b.get(); } friend istream& operator>>(istream& is, mint& b) { int64_t val; is >> val; b = mint(val); return is; } }; using mint = MontgomeryModInt<998244353>; //source: KACTL(for det() and inv()) template struct matrix : vector> { matrix(int n, int m) : vector>(n, vector(m, 0)) {} matrix(int n) : vector>(n, vector(n, 0)) {} int n() const { return ssize(*this); } int m() const { return ssize((*this)[0]); } static matrix I(int n) { auto res = matrix(n, n); for(int i = 0; i < n; i++) res[i][i] = 1; return res; } matrix& operator+=(const matrix &b) { assert(n() == b.n()); assert(m() == b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < m(); j++) (*this)[i][j] += b[i][j]; return *this; } matrix& operator-=(const matrix &b) { assert(n() == b.n()); assert(m() == b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < m(); j++) (*this)[i][j] -= b[i][j]; return *this; } matrix& operator*=(const matrix &b) { assert(m() == b.n()); auto res = matrix(n(), b.m()); for(int i = 0; i < n(); i++) for(int j = 0; j < b.m(); j++) for(int k = 0; k < m(); k++) res[i][j] += (*this)[i][k] * b[k][j]; this -> swap(res); return *this; } matrix pow(ll k) const { assert(n() == m()); auto res = I(n()), base = *this; while(k) { if (k & 1) res *= base; base *= base, k >>= 1; } return res; } Mint det() const { Mint res = 1; auto a = *this; for(int i = 0; i < n(); i++) { for(int j = i + 1; j < m(); j++) { while(a[j][i] != 0) { Mint t = a[i][i] / a[j][i]; if (t != 0) for(int k = i; k < n(); k++) a[i][k] -= a[j][k] * t; swap(a[i], a[j]); res = -res; } } res *= a[i][i]; if (res == 0) return 0; } return res; } matrix inv() const { assert(n() == m()); matrix a = *this, tmp = I(n()); vector col(n()); for(int i = 0; i < n(); i++) col[i] = i; for(int i = 0; i < n(); i++) { int r = i, c = i; for(int j = i; j < n(); j++) { for(int k = i; k < n(); k++) { if (a[j][k] != 0) { r = j, c = k; goto found; } } } return matrix(0); found: a[i].swap(a[r]), tmp[i].swap(tmp[r]); for(int j = 0; j < n(); j++) swap(a[j][i], a[j][c]), swap(tmp[j][i], tmp[j][c]); swap(col[i], col[c]); Mint v = 1 / a[i][i]; for(int j = i + 1; j < n(); j++) { Mint f = a[j][i] * v; a[j][i] = 0; for(int k = i + 1; k < n(); k++) a[j][k] -= f * a[i][k]; for(int k = 0; k < n(); k++) tmp[j][k] -= f * tmp[i][k]; } for(int j = i + 1; j < n(); j++) a[i][j] *= v; for(int j = 0; j < n(); j++) tmp[i][j] *= v; a[i][i] = 1; } for(int i = n() - 1; i > 0; i--) { for(int j = 0; j < i; j++) { Mint v = a[j][i]; for(int k = 0; k < n(); k++) tmp[j][k] -= v * tmp[i][k]; } } for(int i = 0; i < n(); i++) for(int j = 0; j < n(); j++) a[col[i]][col[j]] = tmp[i][j]; return a; } matrix operator-() { return matrix(n(), m()) - (*this); } friend matrix operator+(matrix a, matrix b) { return a += b; } friend matrix operator-(matrix a, matrix b) { return a -= b; } friend matrix operator*(matrix a, matrix b) { return a *= b; } friend ostream& operator<<(ostream& os, const matrix& b) { for(int i = 0; i < b.n(); i++) { os << '\n'; for(int j = 0; j < b.m(); j++) os << b[i][j] << ' '; } return os; } friend istream& operator>>(istream& is, matrix& b) { for(int i = 0; i < b.n(); i++) for(int j = 0; j < b.m(); j++) is >> b[i][j]; return is; } }; const int MAX = 10000001; mint f[MAX]; signed main() { ios::sync_with_stdio(false), cin.tie(NULL); f[0] = 1, f[1] = 2; for(int i = 2; i < MAX; i++) f[i] = f[i - 1] * (2 * i) + f[i - 2] * (i - 1); int t; cin >> t; while(t--) { ll n, m; cin >> n >> m; if (min(n, m) == 0) { cout << 1 << '\n'; continue; } if (n > m) swap(n, m); matrix M(2, 2), x(2, 1); M[0][1] = 1, M[1][0] = n, M[1][1] = 2 * n + 1; x[0][0] = f[n - 1], x[1][0] = f[n]; auto b = M.pow(m - n) * x; cout << f[n] * b[1][0] + f[n - 1] * b[0][0] * n << '\n'; } return 0; }