#include #include using namespace std; using namespace atcoder; // using mint = modint1000000007; // const int mod = 1000000007; using mint = modint998244353; const int mod = 998244353; // const int INF = 1e9; // const long long LINF = 1e18; #define rep(i, n) for (int i = 0; i < (n); ++i) #define rep2(i, l, r) for (int i = (l); i < (r); ++i) #define rrep(i, n) for (int i = (n)-1; i >= 0; --i) #define rrep2(i, l, r) for (int i = (r)-1; i >= (l); --i) #define all(x) (x).begin(), (x).end() #define allR(x) (x).rbegin(), (x).rend() #define P pair template inline bool chmax(A &a, const B &b) { if (a < b) { a = b; return true; } return false; } template inline bool chmin(A &a, const B &b) { if (a > b) { a = b; return true; } return false; } std::vector sieveOfEratosthenes(long long n = 1000000) { std::vectorp(n + 1, true); std::vectorret; p[0] = false; p[1] = false; for (int i = 2; i <= n; ++i) { if (!p[i]) continue; ret.push_back(i); for (int j = 2 * i; j <= n; j += i) p[j] = false; } return ret; } //long long にしているのは p*pとかでこまらないように #include template std::vector> matrixMul(const std::vector>&A, const std::vector>&B) { std::vector> C(A.size(), std::vector(B[0].size())); for (int i = 0; i < (int)A.size(); ++i) { for (int k = 0; k < (int)A[0].size(); ++k) { for (int j = 0; j < (int)B[0].size(); ++j) { C[i][j] += A[i][k] * B[k][j]; } } } return C; } template std::vector> matrixPow(long long n, const std::vector> &mat) { int size = (int)mat.size(); vector> mret(size, vector(size)); for (int i = 0; i < size; ++i) { mret[i][i] = 1; } auto cmat = mat; while (n > 0) { if (1 & n) mret = matrixMul(cmat, mret); cmat = matrixMul(cmat, cmat); n >>= 1; } return mret; } #pragma once #include #include #include #include namespace stl { namespace sorted_vector { // x と等しい要素の個数 template std::size_t count_equal(const std::vector& v, const T& x) { auto l = std::lower_bound(v.begin(), v.end(), x); auto r = std::upper_bound(v.begin(), v.end(), x); return std::distance(l, r); } // x 未満の個数 template std::size_t count_less(const std::vector& v, const T& x) { return std::distance(v.begin(), std::lower_bound(v.begin(), v.end(), x)); } // x 以下の個数 template std::size_t count_leq(const std::vector& v, const T& x) { return std::distance(v.begin(), std::upper_bound(v.begin(), v.end(), x)); } // x 以上の個数 template std::size_t count_geq(const std::vector& v, const T& x) { return std::distance(std::lower_bound(v.begin(), v.end(), x), v.end()); } // x より大きい個数 template std::size_t count_greater(const std::vector& v, const T& x) { return std::distance(std::upper_bound(v.begin(), v.end(), x), v.end()); } // [l, r) に含まれる個数 template std::size_t count_range(const std::vector& v, const T& l, const T& r) { auto L = std::lower_bound(v.begin(), v.end(), l); auto R = std::lower_bound(v.begin(), v.end(), r); return std::distance(L, R); } // 存在判定(1個以上あるか) template bool contains(const std::vector& v, const T& x) { auto it = std::lower_bound(v.begin(), v.end(), x); return it != v.end() && *it == x; } // 最初の出現位置(なければ v.size()) template std::size_t first_index(const std::vector& v, const T& x) { auto it = std::lower_bound(v.begin(), v.end(), x); return (it != v.end() && *it == x) ? std::size_t(it - v.begin()) : v.size(); } // 最後の出現位置(なければ v.size()) template std::size_t last_index(const std::vector& v, const T& x) { auto it = std::upper_bound(v.begin(), v.end(), x); if (it == v.begin()) return v.size(); --it; return (*it == x) ? std::size_t(it - v.begin()) : v.size(); } // x 未満のうち最大の要素 template auto it_less(const std::vector& v, const T& x) { auto it = std::lower_bound(v.begin(), v.end(), x); if (it == v.begin()) return v.end(); --it; return it; } // x 以下のうち最大の要素 template auto it_leq(const std::vector& v, const T& x) { auto it = std::upper_bound(v.begin(), v.end(), x); if (it == v.begin()) return v.end(); --it; return it; } // x 以上のうち最小の要素 template auto it_geq(const std::vector& v, const T& x) { return std::lower_bound(v.begin(), v.end(), x); } // x より大きい最小の要素 template auto it_greater(const std::vector& v, const T& x) { return std::upper_bound(v.begin(), v.end(), x); } // x の最初の出現位置(なければ v.end()) template auto it_first(const std::vector& v, const T& x) { auto it = std::lower_bound(v.begin(), v.end(), x); if (it != v.end() && *it == x) return it; return v.end(); } // x の最後の出現位置(なければ v.end()) template auto it_last(const std::vector& v, const T& x) { auto it = std::upper_bound(v.begin(), v.end(), x); if (it == v.begin()) return v.end(); --it; if (*it == x) return it; return v.end(); } } // namespace sorted_vector } // namespace stl int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t; cin >> t; vectorp0, p1, p2, p3, p4; auto ps = sieveOfEratosthenes(10000000); vectorp; rep(i, ps.size() - 1) { if (ps[i] % 4 != 1)continue; if (ps[i] + 2 == ps[i + 1]) { p.push_back(ps[i]); p.push_back(ps[i + 1]); } } while (t--) { int n, m; cin >> n >> m; if (n == 1) { int ans = stl::sorted_vector::count_leq(ps, m); cout << ans << endl; continue; } int c = stl::sorted_vector::count_leq(p, m); if (m % 4 == 1 && stl::sorted_vector::contains(p, m)) { c--; } else if (m % 4 == 2 && stl::sorted_vector::contains(p, m - 1)) { c--; } vector> mat = { {1,1},{c,0} }; mat = matrixPow(n - 1, mat); mint ans = c * (mat[0][0] + mat[0][1]); ans += 1 * (mat[1][0] + mat[1][1]); cout << ans.val() << endl; } return 0; }