#line 1 "b.cpp" #include "bits/stdc++.h" using namespace std; namespace util { using ll = long long; using vl = std::vector; using pl = std::pair; } // namespace util using namespace util; #include #line 1 "cp-library/binomial.hpp" #include #include template class Binomial { private: int size_, mod_; std::vector fact_, fact_inv_, inv_; public: explicit Binomial(int size) : size_(size), mod_(T::mod()) { fact_.resize(size + 1); fact_inv_.resize(size + 1); inv_.resize(size + 1); fact_[0] = fact_[1] = 1; fact_inv_[0] = fact_inv_[1] = 1; inv_[1] = 1; for (int i = 2; i <= size; ++i) { fact_[i] = fact_[i - 1] * i; inv_[i] = T(mod_) - inv_[mod_ % i] * (mod_ / i); fact_inv_[i] = fact_inv_[i - 1] * inv_[i]; } } T Calc(int n, int k) { assert(n <= size_); if (k < 0 || n < 0 || n < k) return 0; if (k == 0) { return 1; } return fact_[n] * fact_inv_[n - k] * fact_inv_[k]; } T Factorial(int k) { assert(k >= 0 && k <= size_); return fact_[k]; } T FactorialInv(int k) { assert(k >= 0 && k <= size_); return fact_inv_[k]; } }; #line 2 "cp-library/cutils.hpp" #include constexpr long long kMax = std::numeric_limits::max(); inline long long CountDigit(long long n, const long long base = 10) { assert(n > 0); assert(base > 1); long long res = 0; while (n) { res++; n /= base; } return res; } // verified inline long long Pow(long long x, long long n) { assert(n >= 0); if (x == 0) return 0; long long res = 1LL; while (n > 0) { if (n & 1) { assert(x != 0 && std::abs(res) <= kMax / std::abs(x)); res = res * x; } if (n >>= 1) { assert(x != 0 && std::abs(x) <= kMax / std::abs(x)); x = x * x; } } return res; } // verified inline long long Mod(long long n, const long long m) { // returns the "arithmetic modulo" // for a pair of integers (n, m) with m != 0, there exists a unique pair of // integer (q, r) s.t. n = qm + r and 0 <= r < |m| returns this r assert(m != 0); if (m < 0) return Mod(n, -m); if (n >= 0) return n % m; else return (m + n % m) % m; } inline long long Quotient(long long n, long long m) { // returns the "arithmetic quotient" assert((n - Mod(n, m)) % m == 0); return (n - Mod(n, m)) / m; } inline long long DivFloor(long long n, long long m) { // returns floor(n / m) assert(m != 0); if (m < 0) { n = -n; m = -m; } if (n >= 0) return n / m; else if (n % m == 0) return -(std::abs(n) / m); else return -(std::abs(n) / m) - 1; } inline long long DivCeil(long long n, long long m) { // returns ceil(n / m) assert(m != 0); if (n % m == 0) return DivFloor(n, m); else return DivFloor(n, m) + 1; } inline long long PowMod(long long x, long long n, const long long m) { assert(n >= 0); assert(m != 0); if (x == 0) return 0; long long res = 1; x = Mod(x, m); while (n > 0) { if (n & 1) { assert(x == 0 || std::abs(res) <= kMax / std::abs(x)); res = Mod(res * x, m); } if (n >>= 1) { assert(x == 0 || std::abs(x) <= kMax / std::abs(x)); x = Mod(x * x, m); } } return res; } long long SqrtFloor(long long n) { // n -> floor(sqrt(n)) assert(n >= 0); if (n == 0) return 0; long long ok = 0; long long ng = n + 1; while (ng - ok > 1) { long long mid = (ok + ng) / 2; if (mid <= n / mid) { ok = mid; } else { ng = mid; } } return ok; } long long SqrtCeil(long long n) { // n -> ceil(sqrt(n)) assert(n >= 0); if (n == 0) return 0; long long ok = n; long long ng = 0; while (ok - ng > 1) { long long mid = (ok + ng) / 2; if (mid >= n / mid) { ok = mid; } else { ng = mid; } } return ok; } #line 14 "b.cpp" using namespace atcoder; using mint = modint998244353; void solve() { ll n, m; cin >> n >> m; mint ans = 0; Binomial binom(n + 1); for (ll y = -n; y <= n; ++y) { if (m + y * y < 0) continue; if (SqrtCeil(m + y * y) != SqrtFloor(m + y * y)) continue; ll x = SqrtCeil(m + y * y); if ((x + y + n) % 2) continue; ans += binom.Calc(n, (x + y + n) / 2) * binom.Calc(n, (x - y + n) / 2); if (x != 0) { ans += binom.Calc(n, (-x + y + n) / 2) * binom.Calc(n, (-x - y + n) / 2); } } ans *= mint(4).inv().pow(n); cout << ans.val() << '\n'; } int main() { std::cin.tie(nullptr); std::ios::sync_with_stdio(false); std::cout << std::fixed << std::setprecision(15); solve(); return 0; }