#include #include #include #include using namespace std; using ll = long long; const ll INF = 1ll << 60; template ll max_f_true(const F& f, ll ok, ll ng){ while(ok + 1 < ng){ ll wj = (ok + ng) / 2; (f(wj) ? ok : ng) = wj; } return ok; } template ll expsearch(const F& f, ll maxval = INF){ ll l = 0, r = 1; while(r < maxval && f(r)){ l = r; r *= 2; r = min(r, maxval); } return max_f_true(f, l, r); } struct ConvexEdge { ll dx; ll dy; ll count; }; struct Convex { vector edges; }; // x,y 両方に関して単調増加凸関数 f について、 // 0 <= x, 0 <= y , f(x,y) < 0 なる (x,y) の集合の凸包を求める。 // start, end はともに f(x,y) < 0 を満たし、探索領域の右下と左上を指す。 template Convex ConvexTrace( const F& f, pair start, pair end ){ ll minx = end.first; ll maxx = start.first; ll maxy = end.second; auto det = [&](ll x, ll y) -> bool { return f(x,y) < 0; }; auto inrange = [&](ll x, ll y) -> bool { return minx <= x && y <= maxy; }; auto fp = [&](ll x, ll y){ return x <= maxx && y <= maxy && (x < minx || y < 0 || det(x, y)); }; Convex res; ll x = start.first, y = start.second; struct Node { ll ldx, ldy, rdx, rdy; }; vector sch; sch.push_back({ 0, 1, 1, 0 }); { ll w = expsearch([&](ll t){ return fp(maxx, y + t); }); if(w){ y += w; res.edges.push_back({ 0, 1, w }); } } while(minx < x && y < maxy && sch.size()){ auto v = sch.back(); if(!fp(x - v.rdx, y + v.rdy)){ sch.pop_back(); continue; } ll maxlsh = expsearch([&](ll t){ return fp(x - v.ldx * t - v.rdx, y + v.ldy * t + v.rdy); }); if(maxlsh >= 1){ ll nxdx = v.ldx * maxlsh + v.rdx; ll nxdy = v.ldy * maxlsh + v.rdy; sch.push_back({ nxdx + v.ldx, nxdy + v.ldy, nxdx, nxdy }); continue; } auto pred = [&](ll t) -> bool { ll qx = x - v.ldx - v.rdx * t, qy = y + v.ldy + v.rdy * t; if(!inrange(qx - v.rdx, qy + v.rdy)) return 0; ll lval = f(qx, qy); if(lval < 0) return 0; ll rval = f(qx - v.rdx, qy + v.rdy); return rval < lval; }; ll t = expsearch(pred); Node nx = { v.ldx + v.rdx * t, v.ldy + v.rdy * t, v.ldx + v.rdx * (t+1), v.ldy + v.rdy * (t+1) }; if(inrange(x - nx.rdx, y + nx.rdy) && f(x - nx.rdx, y + nx.rdy) < 0){ sch.push_back(nx); continue; } ll w = expsearch([&](ll w){ return fp(x - v.rdx * w, y + v.rdy * w); }); if(w){ res.edges.push_back({ v.rdx, v.rdy, w }); x -= v.rdx * w; y += v.rdy * w; } sch.pop_back(); } if(end.first < x) res.edges.push_back({ 1, 0, x - end.first }); return res; } const int MOD = 998244353; void testcase(){ ll N; cin >> N; auto det = [&](ll a, ll b) -> bool { return __int128_t(a) * b * 2 + a + b <= N; }; auto maxb = [&](ll a) -> ll { return expsearch([a,det](ll b){ return det(a, b); }); }; ll maxdiag = expsearch([&](ll x){ return det(x,x); }); ll max1b = expsearch([&](ll x){ return det(1,x); }); auto tr = [&](ll x){ return max1b + 1 - x; }; auto convexdet = [&](ll x, ll y) -> __int128_t { ll a = max1b + 1 - x, b = max1b + 1 - y; return N - __int128_t(a) * b * 2 - a - b; }; ll naive_lim = min(maxdiag, 10000000); ll offset = naive_lim + 1; pair ct_start = { maxb(offset) + 1, offset }; ll ans = 0; for(ll i=1; i<=naive_lim; i++){ ans += (((N * 2 + 1) / (i * 2 + 1) - 1) / 2 - i) * 2; ans %= MOD; } ans += naive_lim; auto ch = ConvexTrace(convexdet, {tr(maxdiag+1), tr(maxdiag+1)}, {tr(ct_start.first), tr(ct_start.second)}); reverse(ch.edges.begin(), ch.edges.end()); ll onborder = (ct_start.first - 1 - offset + 1) - 1; ll area = 0; { ll px = ct_start.first - offset, py = ct_start.second - offset; for(auto v : ch.edges){ onborder -= v.count; ll qx = px - v.count * v.dx; ll qy = py + v.count * v.dy; area += (px % MOD * (qy % MOD) % MOD) - (py % MOD * (qx % MOD) % MOD); px = qx; py = qy; } } area += onborder; area += 1; area = (area % MOD + MOD) % MOD; ans = (ans + area) % MOD; cout << ans << "\n"; } int main(){ cin.tie(0)->sync_with_stdio(0); int T; cin >> T; for(int i=0; i