Problem:
Score : 700 points

Problem Statement

Takahashi throws N dice, each having K sides with all integers from 1 to K. The dice are NOT pairwise distinguishable.
For each i=2,3,...,2K, find the following value modulo 998244353:

The number of combinations of N sides shown by the dice such that the sum of no two different sides is i.

Note that the dice are NOT distinguishable, that is, two combinations are considered different when there exists an integer k such that the number of dice showing k is different in those two.

Constraints

1 \leq K \leq 2000

2 \leq N \leq 2000

K and N are integers.

Input

Input is given from Standard Input in the following format:

K N

Output

Print 2K-1 integers. The t-th of them (1\leq t\leq 2K-1) should be the answer for i=t+1.

Sample Input 1

3 3

Sample Output 1

7
7
4
7
7

For i=2, the combinations (1,2,2),(1,2,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3) satisfy the condition, so the answer is 7.

For i=3, the combinations (1,1,1),(1,1,3),(1,3,3),(2,2,2),(2,2,3),(2,3,3),(3,3,3) satisfy the condition, so the answer is 7.

For i=4, the combinations (1,1,1),(1,1,2),(2,3,3),(3,3,3) satisfy the condition, so the answer is 4.

Sample Input 2

4 5

Sample Output 2

36
36
20
20
20
36
36

Sample Input 3

6 1000

Sample Output 3

149393349
149393349
668669001
668669001
4000002
4000002
4000002
668669001
668669001
149393349
149393349

Solution in Rust (1.15.1) (judge verdict: Accepted)

// from https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        input_inner!{iter, $($r)*}
    };
    ($($r:tt)*) => {
        let mut 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)*}
    };
}

macro_rules! input_inner {
    ($iter:expr) => {};
    ($iter:expr, ) => {};

    ($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($iter, $t);
        input_inner!{$iter $($r)*}
    };
}

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) => {
        read_value!($iter, String).chars().collect::<Vec<char>>()
    };

    ($iter:expr, usize1) => {
        read_value!($iter, usize) - 1
    };

    ($iter:expr, $t:ty) => {
        $iter.next().unwrap().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused_macros)]
macro_rules! debug { ($x: expr) => { println!("{}: {:?}", stringify!($x), $x) } }
// macro_rules! debug { ($x: expr) => () }

#[allow(dead_code)]
fn show<T>(iter: T) -> String
where
    T: Iterator,
    T::Item: std::fmt::Display
{
    let mut res = iter.fold(String::new(), |sum, e| sum + &format!("{} ", e));
    res.pop();
    res
}

#[allow(unused_imports)]
use std::cmp::{max, min};
#[allow(unused_imports)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
#[allow(unused_imports)]
use std::collections::btree_map::Entry::{Occupied, Vacant};


macro_rules! make_modint {
    ($MOD: expr, $name: ident) => {
        #[derive(Ord, Hash, Eq, PartialOrd, PartialEq)]
        struct $name {
            val: i64,
        }

        impl $name {
            fn new(x: i64) -> $name {
                let x = x%$MOD;
                $name{val: if x < 0 { x+$MOD } else { x }}
            }

            fn pow(&self, x: i64) -> $name {
                let mut res = $name::new(1);
                let mut tmp = x;
                let mut p = *self;
                while tmp != 0 {
                    if tmp&1 == 1 {
                        res *= p;
                    }
                    tmp = tmp>>1;
                    p = p*p;
                }
                res
            }

            fn inv(&self) -> $name {
                assert!(self.val != 0);
                let mut a = self.val;
                let mut b = $MOD;
                let mut u = 1;
                let mut v = 0;
                use std::mem::swap;
                while b != 0 {
                    let t = a/b;
                    a -= t*b;
                    swap(&mut a, &mut b);
                    u -= t*v;
                    swap(&mut u, &mut v);
                }
                $name::new(u)
            }
        }

        impl std::clone::Clone for $name {
            fn clone(&self) -> $name {
                $name{ val: self.val }
            }
        }

        impl std::marker::Copy for $name { }

        impl std::ops::Add for $name {
            type Output = $name;
            fn add(self, y: $name) -> $name {
                let tmp = self.val+y.val;
                $name{val: if tmp >= $MOD {tmp-$MOD} else {tmp}}
            }
        }

        impl std::ops::Neg for $name {
            type Output = $name;
            fn neg(self) -> $name {
                $name::new(self.val)
            }
        }

        impl std::ops::Sub for $name {
            type Output = $name;
            fn sub(self, other: $name) -> $name{
                let tmp = self.val-other.val;
                $name{val: if tmp < 0 {tmp+$MOD} else {tmp}}
            }
        }

        impl std::ops::Mul for $name {
            type Output = $name;
            fn mul(self, y: $name) -> $name {
                $name{val: (self.val*y.val)%$MOD}
            }
        }

        impl std::ops::Div for $name {
            type Output = $name;
            fn div(self, other: $name) -> $name {
                self*other.inv()
            }
        }

        impl std::fmt::Display for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "{}", self.val)
            }
        }

        impl std::ops::AddAssign for $name {
        fn add_assign(&mut self, other: $name) {
            *self = *self+other;
        }
        }

        impl std::ops::SubAssign for $name {
            fn sub_assign(&mut self, other: $name) {
                *self = *self-other;
            }
        }

        impl std::ops::MulAssign for $name {
            fn mul_assign(&mut self, other: $name) {
                *self = *self*other;
            }
        }

        impl std::ops::DivAssign for $name {
            fn div_assign(&mut self, other: $name) {
                *self = *self*other.inv();
            }
        }

        impl std::fmt::Debug for $name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "{}", self.val)
            }
        }
    }
}

make_modint!(998244353, ModInt);

fn mint(x: i64) -> ModInt {
    ModInt::new(x)
}

mod algebra {
    use std::ops::{Add, Div, Mul, Neg, Sub};
    use std;

    pub trait Zero {
        fn zero() -> Self;
    }

    pub trait Monoid: Add<Self, Output = Self> + Zero
    where
        Self: std::marker::Sized,
    {}

    pub trait Group: Monoid + Neg<Output = Self> + Sub<Self, Output = Self> {}

    pub trait Ring: Group + One + Mul<Self, Output = Self> {}

    pub trait One {
        fn one() -> Self;
    }

    pub trait Field: Ring + Div<Self, Output = Self> {}
    
    impl<T: Add<T, Output = T> + Zero> Monoid for T {}
    impl<T: Monoid + Neg<Output = T> + Sub<T, Output = T>> Group for T {}
    impl<T: Group + One + Mul<T, Output = T>> Ring for T {}
    impl<T: Ring + Div<T, Output = T>> Field for T {}
}


impl algebra::One for ModInt {
    // const ONE: ModInt = ModInt { val: 1 };
    fn one() -> Self { ModInt{val: 1} }
}

impl algebra::Zero for ModInt {
    fn zero() -> Self { ModInt{val: 0} }
}




trait MapToi64 {
    fn map_to_number(i64) -> Self;
}

impl MapToi64 for ModInt {
    fn map_to_number(x: i64) -> ModInt {
        ModInt::new(x)
    }
}

#[derive(Debug)]
struct ConvQuery<T>
where
    T: algebra::Field,
{
    fac: Vec<T>,
    facinv: Vec<T>,
}

impl<T> ConvQuery<T>
where
    T: algebra::Field + MapToi64 + std::clone::Clone,
{
    fn new(n: usize) -> Self {
        let mut fac = Vec::with_capacity(n + 1);
        let mut facinv = Vec::with_capacity(n + 1);
        fac.push(T::one());
        for x in 1..n + 1 {
            let num = {
                let last = fac.last().unwrap();
                (*last).clone() * T::map_to_number(x as i64)
            };
            fac.push(num.clone());
        }
        let mut num = T::one() / fac.last().unwrap().clone();
        facinv.push(num.clone());
        for i in (0..n).rev() {
            num = num * T::map_to_number((i + 1) as i64);
            facinv.push(num.clone());
        }
        facinv.reverse();
        ConvQuery {
            fac: fac,
            facinv: facinv,
        }
    }

    fn query(&self, n: usize, m: usize) -> T {
        self.fac[n].clone() * self.facinv[n - m].clone() * self.facinv[m].clone()
    }
}


fn main() {
    use std::io::Write;
    let out = std::io::stdout();
    let mut out = std::io::BufWriter::new(out.lock());
    macro_rules! printf { ($($arg:tt)*) => (write!(out, $($arg)*).unwrap()); }
    macro_rules! printfln { () => (writeln!(out).unwrap()); ($($arg:tt)*) => (writeln!(out, $($arg)*).unwrap()); }
    
    input! {
        k: usize,
        n: usize,
    }

    let mut dp = vec![vec![mint(0); n+1]; k+1];

    dp[0][0] = mint(1);

    for i in 0..k {
        let mut sum = mint(0);
        sum += dp[i][0];
        dp[i+1][0] = sum;
        for j in 1..n+1 {
            sum += dp[i][j]; 
            dp[i+1][j] = mint(2)*sum - dp[i][j];
        }
    }

    // dp.iter().for_each(|x| debug!(x));

    let co = ConvQuery::new(n+k+1);


    // let f = |n, k| {
    //     co.query(n-1, k-1)
    // };

    let f = |n, k| {
        if k == 0 {
            if n == 0 {
                mint(1)
            } else {
                mint(0)
            }
        } else {
            co.query(n+k-1, k-1)
        }
    };

    let mut v = vec![];

    for i in 2..(k+2) {
        let k2 = (i-1)/2;

        if i%2 == 0 {
            let rk = k-k2*2-1;
            let mut ans = mint(0);

            for x in 0..n+1 {
                ans += dp[k2][x] * f(n-x, rk);
            }

            for x in 0..n {
                ans += dp[k2][x] * f(n-x-1, rk);
            }

            printfln!("{}", ans);
            v.push(ans);
        } else {
            let rk = k-k2*2;
            let mut ans = mint(0);

            for x in 0..n+1 {
                ans += dp[k2][x] * f(n-x, rk);
            }

            printfln!("{}", ans);
            v.push(ans);
        }
    }

    

    for &e in v.iter().rev().skip(1) {
        printfln!("{}", e);
    }
}