#include #include using namespace std; using ll = long long; using mint = atcoder::modint998244353; struct Vc { ll x, y; friend Vc operator+(const Vc& lhs, const Vc& rhs) { return {lhs.x + rhs.x, lhs.y + rhs.y}; } friend Vc operator*(ll a, const Vc& v) { return {a * v.x, a * v.y}; } bool operator==(const Vc&) const = default; }; struct S { Vc inCand, out; }; void lattice_hull(Vc start, vector sbtree, auto op, auto is_inside, auto get_t_cand, int t_margin = 0) { auto find_max_true = [](auto pred) { // l = 0 -> true ll l = 0, r = 1; while (pred(r)) l = r, r *= 2; while (r - l > 1) { auto c = midpoint(l, r); (pred(c) ? l : r) = c; } return l; }; auto find_min_true = [](auto pred, ll ub) { // l = 0 -> false // search in [1, ub] ll l = 0, r = 1; while (!pred(r)) { if (r == ub) return -1LL; l = r, r = min(2 * r, ub); } while (r - l > 1) { auto c = midpoint(l, r); (pred(c) ? r : l) = c; } return r; }; auto v = start; while (true) { while (!sbtree.empty() && !is_inside(v + sbtree.back().inCand)) { sbtree.pop_back(); } if (sbtree.empty()) break; bool now_inside = is_inside(v + sbtree.back().inCand + sbtree.back().out); while (true) { auto [vin, vout] = sbtree.back(); if (now_inside) { ll t = find_max_true( [&](ll t) { return is_inside(v + vin + (t + 1) * vout); }); sbtree.emplace_back(vin + (t + 1) * vout, vout); now_inside = false; } else { ll ub = get_t_cand(v + vin + vout, vin); auto pred = [&](ll t) { // v + (t+1)vin + vout ll x, y; if (__builtin_mul_overflow(t + 1, vin.x, &x) || __builtin_mul_overflow(t + 1, vin.y, &y) || __builtin_add_overflow(x, v.x + vout.x, &x) || __builtin_add_overflow(y, v.y + vout.y, &y)) return false; return is_inside(Vc{x, y}); }; ll t = ub >= 1 ? find_min_true(pred, ub) : -1LL; if (t == -1) { for (int dt = 1; dt <= t_margin; dt++) { if (ub + dt >= 1 && pred(ub + dt)) { t = ub + dt; break; } } if (t == -1) break; } sbtree.emplace_back(vin, t * vin + vout); now_inside = true; } } auto w = sbtree.back().inCand; ll t = find_max_true([&](ll t) { return is_inside(v + (t + 1) * w); }) + 1; op(v, v + t * w, t); v = v + t * w; } } auto floor_div(signed_integral auto x, signed_integral auto y) { return x / y - ((x ^ y) < 0 && x % y != 0); } auto ceil_div(signed_integral auto x, signed_integral auto y) { return x / y + ((x ^ y) >= 0 && x % y != 0); } mint solve(ll n) { // x(y+1)+y(x+1) > n // (2x+1)(2y+1) > 2n+1 // (2x+1)^2 <= 2n+1 // <=> x <= (sqrt(2n+1)-1)/2 ll c = ((ll)sqrtl(2 * n + 1) - 1) / 2; Vc start{c + 1, (c + 2 + n) / (2 * c + 3)}; mint ans; ans += start.y - 1; const mint inv2 = mint(2).inv(); constexpr int YMIN = 1000000; // (2x+1)(2YMIN+1)=2n+1 ll xmx = min(n, max(((2*n+1)/(2*YMIN+1)-1)/2, c+1)); auto op = [&](Vc u, Vc v, ll t) { ll dx = v.x - u.x, dy = u.y - v.y; ans += mint(dx) * u.y - (mint(dx + 1) * (dy + 1) + t - 1) * inv2; }; auto is_inside = [&](Vc v) { ll z; return v.x <= xmx && v.y > 0 && !__builtin_mul_overflow(2 * v.x + 1, 2 * v.y + 1, &z) && z > 2 * n + 1; }; auto get_t_cand = [&](Vc p, Vc v) { ll t; if (v.y == 0) { // (2(px+t)+1)(2py+1) > 2n+1 t = (floor_div(2 * n + 1, 2 * p.y + 1) - 1) / 2 - p.x; } else { // (2(px+tvx)+1)(2(py+tvy)+1) > 2n+1 // t = (-px-1/2)/vx = (-2px-1)/2vx t = floor_div( floor_div(-2 * p.x - 1, 2 * v.x) + floor_div(-2 * p.y - 1, 2 * v.y), 2); } ll nx; if (t > 1 && (__builtin_mul_overflow(v.x, t, &nx) || __builtin_add_overflow(nx, p.x, &nx) || nx > xmx)) { // px + tvx <= xmx t = (xmx - p.x) / v.x; } return t; }; lattice_hull(start, {{1, 0, 0, -1}}, op, is_inside, get_t_cand, 1); // (2xmx+1)(2y+1) > 2n+1 int y0 = ((2*n+1)/(2*xmx+1)+1)/2; for (int y = y0; y > 0; y--) { ll x = ((2*n+1)/(2*y+1)+1)/2; ans += max(0LL, x - xmx - 1); } ans = 2 * ans + mint(c).pow(2); return ans; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int tt; cin >> tt; while (tt--) { ll n; cin >> n; cout << solve(n).val() << '\n'; } }