macro_rules !read_value {($iter :expr ,($($t :tt ) ,*) ) =>{($(read_value !($iter ,$t ) ) ,*) } ;($iter :expr ,[$t :tt ;$len :expr ] ) =>{(0 ..$len ) .map (|_ |read_value !($iter ,$t ) ) .collect ::<Vec <_ >>() } ;($iter :expr ,{chars :$base :expr } ) =>{read_value !($iter ,String ) .chars () .map (|c |(c as u8 -$base as u8 ) as usize ) .collect ::<Vec <usize >>() } ;($iter :expr ,{char :$base :expr } ) =>{read_value !($iter ,{chars :$base } ) [0 ] } ;($iter :expr ,chars ) =>{read_value !($iter ,String ) .chars () .collect ::<Vec <char >>() } ;($iter :expr ,char ) =>{read_value !($iter ,chars ) [0 ] } ;($iter :expr ,usize1 ) =>{read_value !($iter ,usize ) -1 } ;($iter :expr ,$t :ty ) =>{$iter .next () .unwrap () .parse ::<$t >() .unwrap () } ;}
macro_rules !input_inner {($iter :expr ) =>{} ;($iter :expr ,) =>{} ;($iter :expr ,mut $var :ident :$t :tt $($r :tt ) *) =>{let mut $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,mut $var :ident $($r :tt ) *) =>{input_inner !{$iter ,mut $var :usize $($r ) *} } ;($iter :expr ,$var :ident :$t :tt $($r :tt ) *) =>{let $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,$var :ident $($r :tt ) *) =>{input_inner !{$iter ,$var :usize $($r ) *} } ;}
macro_rules !input {(source =$s :expr ,$($r :tt ) *) =>{let mut iter =$s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;(iter =$iter :ident ,$($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut $iter =s .split_whitespace () ;input_inner !{$iter ,$($r ) *} } ;($($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut iter =s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;}
const MOD: i64 = 998244353;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Modi64(pub i64);
impl Modi64 {
    #[inline]
    pub fn new(i: i64) -> Self {
        Modi64(Self::modulo(i, MOD))
    }
    #[inline]
    pub fn modulo(i: i64, m: i64) -> i64 {
        let mut x = i % m;
        if x < 0 {
            x += m;
        }
        x
    }
    pub fn pow(self, y: i64) -> Self {
        let mut y = Self::modulo(y, MOD - 1);
        let mut x = Self::new(1);
        let mut base = self;
        while y > 0 {
            if y & 1 == 1 {
                x *= base;
            }
            base *= base;
            y = y >> 1;
        }
        x
    }
    #[inline]
    pub fn inv(self) -> Self {
        let (mut x, mut s, mut t, mut u) = (1, self.0, MOD, 0);
        while t != 0 {
            let k = s / t;
            s -= k * t;
            std::mem::swap(&mut s, &mut t);
            x -= k * u;
            std::mem::swap(&mut x, &mut u);
        }
        Modi64::new(x)
    }
}
impl From<i64> for Modi64 {
    fn from(i: i64) -> Self {
        Self::new(i)
    }
}
impl std::ops::Add for Modi64 {
    type Output = Self;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        Modi64((self.0 + rhs.0) % MOD)
    }
}
impl<'a> std::ops::Add<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: Modi64) -> Self::Output {
        *self + rhs
    }
}
impl<'a> std::ops::Add<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: &'a Modi64) -> Self::Output {
        self + *rhs
    }
}
impl<'a> std::ops::Add for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn add(self, rhs: Self) -> Self::Output {
        *self + *rhs
    }
}
impl std::ops::AddAssign for Modi64 {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        *self = *self + rhs;
    }
}
impl<'a> std::ops::AddAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn add_assign(&mut self, rhs: &'a Modi64) {
        *self += *rhs;
    }
}
impl std::ops::Sub for Modi64 {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        Self::new(self.0 - rhs.0)
    }
}
impl<'a> std::ops::Sub<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: Modi64) -> Self::Output {
        *self - rhs
    }
}
impl<'a> std::ops::Sub<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: &'a Modi64) -> Self::Output {
        self - *rhs
    }
}
impl<'a> std::ops::Sub for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        *self - *rhs
    }
}
impl std::ops::SubAssign for Modi64 {
    #[inline]
    fn sub_assign(&mut self, rhs: Self) {
        *self = *self - rhs;
    }
}
impl<'a> std::ops::SubAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn sub_assign(&mut self, rhs: &'a Modi64) {
        *self -= *rhs;
    }
}
impl std::ops::Mul for Modi64 {
    type Output = Self;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        Modi64(self.0 * rhs.0 % MOD)
    }
}
impl<'a> std::ops::Mul<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: Modi64) -> Self::Output {
        *self * rhs
    }
}
impl<'a> std::ops::Mul<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: &'a Modi64) -> Self::Output {
        self * *rhs
    }
}
impl<'a> std::ops::Mul for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn mul(self, rhs: Self) -> Self::Output {
        *self * *rhs
    }
}
impl std::ops::MulAssign for Modi64 {
    #[inline]
    fn mul_assign(&mut self, rhs: Self) {
        *self = *self * rhs;
    }
}
impl<'a> std::ops::MulAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn mul_assign(&mut self, rhs: &'a Modi64) {
        *self *= *rhs;
    }
}
impl std::ops::Div for Modi64 {
    type Output = Self;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        self * rhs.inv()
    }
}
impl<'a> std::ops::Div<Modi64> for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: Modi64) -> Self::Output {
        *self * rhs.inv()
    }
}
impl<'a> std::ops::Div<&'a Modi64> for Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: &'a Modi64) -> Self::Output {
        self * rhs.inv()
    }
}
impl<'a> std::ops::Div for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn div(self, rhs: Self) -> Self::Output {
        *self * rhs.inv()
    }
}
impl std::ops::DivAssign for Modi64 {
    #[inline]
    fn div_assign(&mut self, rhs: Self) {
        *self = *self * rhs.inv();
    }
}
impl<'a> std::ops::DivAssign<&'a Modi64> for Modi64 {
    #[inline]
    fn div_assign(&mut self, rhs: &'a Modi64) {
        *self *= rhs.inv();
    }
}
impl std::ops::Neg for Modi64 {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self::Output {
        Self::new(-self.0)
    }
}
impl<'a> std::ops::Neg for &'a Modi64 {
    type Output = Modi64;
    #[inline]
    fn neg(self) -> Self::Output {
        -*self
    }
}
impl std::iter::Sum for Modi64 {
    #[inline]
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        iter.fold(Self::new(0), std::ops::Add::add)
    }
}
impl<'a> std::iter::Sum<&'a Modi64> for Modi64 {
    #[inline]
    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
        iter.fold(Self::new(0), |x, &y| x + y)
    }
}
impl std::fmt::Display for Modi64 {
    fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> Result<(), std::fmt::Error> {
        write!(f, "{}", self.0)
    }
}
impl std::str::FromStr for Modi64 {
    type Err = std::num::ParseIntError;
    #[inline]
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        s.parse::<i64>().map(|i| Modi64::new(i))
    }
}
#[derive(Clone, Debug)]
pub struct MemorizedFactorial {
    n: usize,
    fact: Vec<Modi64>,
    inv_fact: Vec<Modi64>,
}
impl MemorizedFactorial {
    pub fn new(max_n: usize) -> MemorizedFactorial {
        let mut fact = vec![Modi64::new(1); max_n + 1];
        let mut inv_fact = vec![Modi64::new(1); max_n + 1];
        for i in 1..(max_n + 1) {
            fact[i] = fact[i - 1] * Modi64::new(i as i64);
            inv_fact[i] = inv_fact[i - 1] / Modi64::new(i as i64);
        }
        MemorizedFactorial {
            n: max_n + 1,
            fact: fact,
            inv_fact: inv_fact,
        }
    }
    pub fn combination(&self, n: usize, r: usize) -> Modi64 {
        if r <= n {
            self.fact[n] * self.inv_fact[r] * self.inv_fact[n - r]
        } else {
            Modi64::new(0)
        }
    }
    pub fn permutation(&self, n: usize, r: usize) -> Modi64 {
        if r <= n {
            self.fact[n] * self.inv_fact[n - r]
        } else {
            Modi64::new(0)
        }
    }
    pub fn homogeneous_product(&self, n: usize, r: usize) -> Modi64 {
        if n != 0 && r != 0 {
            self.combination(n + r - 1, r)
        } else {
            Modi64::new(1)
        }
    }
}
fn main() {
    input! { k, n };
    let fact = MemorizedFactorial::new(k + n + 2);
    let mut memo = vec![vec![Modi64::new(0); n + 1]; k + 1];
    memo[0][0] = 1.into();
    let mut sum = memo.clone();
    for j in 1..n + 1 {
        sum[0][j] = sum[0][j - 1];
    }
    for i in 0..k {
        for j in 1..n + 1 {
            memo[i + 1][j] = sum[i][j - 1] + sum[i][j];
        }
        sum[i + 1][0] = sum[i][0];
        for j in 1..n + 1 {
            sum[i + 1][j] = sum[i + 1][j - 1] + memo[i + 1][j];
        }
    }
    for i in 2..2 * k + 1 {
        let i = if i >= k + 1 { 2 * k + 2 - i } else { i };
        let mut ans = Modi64::new(0);
        let mut dp = vec![Modi64::new(0); n + 1];
        dp[0] = 1.into();
        let a = i / 2;
        let y = 1 - i % 2;
        let x = a - y;
        let z = k - 2 * x - y;
        if x > 0 {
            for j in 1..n + 1 {
                dp[j] += memo[x][j];
            }
        }
        if y == 1 {
            for j in (0..n).rev() {
                let d = dp[j];
                dp[j + 1] += d;
            }
        }
        if z > 0 {
            for j in 0..n + 1 {
                ans += dp[j] * fact.combination(z + n - j - 1, n - j);
            }
        } else {
            ans += dp[n];
        }
        println!("{}", ans);
    }
}


Measured memory_bytes: 86268