inline int qmod(int& x) {
return x < mod ? x : x -= mod;
}
template<const int mod = 998244353>
struct FWT{
const int inv2 = ksm(2, mod - 2);
int l;
void init(int n) {
l = 2;
while(l < n) l <<= 1;//l <= n?
}
inline int qmod(int x) {
while(x >= mod) x -= mod;
return x;
}
void fwt(vector<int> &a, int opt, int cas) {
a.resize(l);//l + 1?
int x, y;
for(int k = 2; k <= l; k <<= 1) {
int mid = k >> 1;
for(int i = 0; i < l; i += k) {
for(int j = i, up = i + mid; j < up; ++ j) {
x = a[j], y = a[j + mid];
a[j] = qmod(x + y);
a[j + mid] = qmod(x - y + mod);
if(opt == -1) a[j] = a[j] * inv2 % mod, a[j + mid] = a[j + mid] * inv2 % mod;
}
}
}
}
};
FWT<> f;
//转二进制后,每个1的位置对应的数[2^k, 2^{k + 1} - 1]都能取到,还有就是自己一定取不到
//对于每个数可以拿的次数是1、只有1个1 -> 1. 2、多个1找第二大的1,次数就是这个1加上1
//显然就可以把每堆变为他可以拿的次数,显然每堆的次数异或为0算1个贡献,求出的次数作为下标的值通过fwt求即可
//必须取mx,不然复杂度不对的
signed main() {
int n = rd(), m = rd(), mx = 0;//n个数的集合,每个数范围[1, m]
vector<int> a(m + 1);
for(int i = 1, now = 1; i <= m; ++ i) {
if(i > now && i % now == 0) now <<= 1;
a[i - now + 1] ++; mx = max(mx, i - now + 1);
}
//nim博弈,每堆异或不为0必胜!
f.init(mx + 1);
f.fwt(a, 1, 3); n %= (mod - 1);
for(int i = 0; i < f.l; ++ i) a[i] = ksm(a[i], n);
f.fwt(a, -1, 3);
int ans = 0;
for(int i = 1; i < f.l; ++ i) ans += a[i];
printf("%lld\n", ans % mod);
return 0;
}