Problem:
Score : 100 points

Problem Statement

You are given two integer arrays a_0, a_1, ..., a_{N - 1} and b_0, b_1, ..., b_{M - 1}. Calculate the array c_0, c_1, ..., c_{(N - 1) + (M - 1)}, defined by c_i = \sum_{j = 0}^i a_j b_{i - j} \bmod 998244353.

Constraints

1 \leq N, M \leq 524288

0 \leq a_i, b_i < 998244353

All values in Input are integer.

Input

Input is given from Standard Input in the following format:

N M
a_0 a_1 ... a_{N-1}
b_0 b_1 ... b_{M-1}

Output

Print the answer in the following format:

c_0 c_1 ... c_{(N - 1) + (M - 1)}

Sample Input 1

4 5
1 2 3 4
5 6 7 8 9

Sample Output 1

5 16 34 60 70 70 59 36

Sample Input 2

1 1
10000000
10000000

Sample Output 2

871938225

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

fn main() {
    let (r, w) = (std::io::stdin(), std::io::stdout());
    let mut sc = IO::new(r.lock(), w.lock());
    let n: usize = sc.read();
    let m: usize = sc.read();
    let a = sc.vec(n);
    let b = sc.vec(m);
    let fft = FastFourierTransform::new(998244353);
    let c = fft.convolution(&a, &b);

    for i in 0..c.len() {
        if i > 0 {
            sc.write(" ");
        }
        sc.write(c[i]);
    }
    sc.write("\n");
}

pub struct FastFourierTransform {
    modulo: i64,
    sum_e: [i64; 30],
    sum_ie: [i64; 30],
}

impl FastFourierTransform {
    pub fn new(modulo: i64) -> Self {
        let primitive_root = primitive_root(modulo);

        let mut es = [0; 30];
        let mut ies = [0; 30];
        let count2 = (modulo - 1).trailing_zeros();
        let mut e = mod_pow(primitive_root, (modulo - 1) >> count2, modulo);
        let mut ie = mod_inv(e, modulo);
        let count2 = count2 as usize;
        for i in (2..=count2).rev() {
            es[i - 2] = e;
            ies[i - 2] = ie;
            e = (e * e) % modulo;
            ie = (ie * ie) % modulo;
        }

        let mut sum_e = [0; 30];
        let mut now = 1;
        for i in 0..=(count2 - 2) {
            sum_e[i] = (es[i] * now) % modulo;
            now = (now * ies[i]) % modulo;
        }

        let mut es = [0; 30];
        let mut ies = [0; 30];
        let count2 = (modulo - 1).trailing_zeros();
        let mut e = mod_pow(primitive_root, (modulo - 1) >> count2, modulo);
        let mut ie = mod_inv(e, modulo);
        let count2 = count2 as usize;
        for i in (2..=count2).rev() {
            es[i - 2] = e;
            ies[i - 2] = ie;
            e = (e * e) % modulo;
            ie = (ie * ie) % modulo;
        }

        let mut sum_ie = [0; 30];
        let mut now = 1;
        for i in 0..=(count2 - 2) {
            sum_ie[i] = (ies[i] * now) % modulo;
            now = (now * es[i]) % modulo;
        }

        Self {
            sum_e,
            modulo,
            sum_ie,
        }
    }
    fn butterfly(&self, a: &mut [i64]) {
        let h = a.len().next_power_of_two().trailing_zeros();
        for ph in 1..=h {
            let w = 1 << (ph - 1);
            let p = 1 << (h - ph);
            let mut now = 1;
            for s in 0..w {
                let offset = s << (h - ph + 1);
                for i in 0..p {
                    let l = a[i + offset] % self.modulo;
                    let r = (a[i + offset + p] * now) % self.modulo;
                    a[i + offset] = (l + r) % self.modulo;
                    a[i + offset + p] = (l + self.modulo - r) % self.modulo;
                }

                now = (self.sum_e[(!s).trailing_zeros() as usize] * now) % self.modulo;
            }
        }
    }

    fn butterfly_inv(&self, a: &mut [i64]) {
        let h = a.len().next_power_of_two().trailing_zeros();
        for ph in (1..=h).rev() {
            let w = 1 << (ph - 1);
            let p = 1 << (h - ph);
            let mut inv_now = 1;
            for s in 0..w {
                let offset = s << (h - ph + 1);
                for i in 0..p {
                    let l = a[i + offset] % self.modulo;
                    let r = a[i + offset + p] % self.modulo;
                    a[i + offset] = (l + r) % self.modulo;
                    a[i + offset + p] =
                        (((l + self.modulo - r) % self.modulo) * inv_now) % self.modulo;
                }

                inv_now = (self.sum_ie[(!s).trailing_zeros() as usize] * inv_now) % self.modulo;
            }
        }
    }

    pub fn convolution(&self, a: &[i64], b: &[i64]) -> Vec<i64> {
        if a.is_empty() || b.is_empty() {
            return Vec::new();
        }

        let n = a.len();
        let m = b.len();

        let z = (n + m - 1).next_power_of_two();
        let mut a = Vec::from(a);
        a.resize(z, 0);
        self.butterfly(&mut a);

        let mut b = Vec::from(b);
        b.resize(z, 0);
        self.butterfly(&mut b);

        for i in 0..z {
            a[i] = (a[i] * b[i]) % self.modulo;
        }

        self.butterfly_inv(&mut a);
        a.resize(n + m - 1, 0);
        let iz = mod_inv(z as i64, self.modulo);
        for i in 0..a.len() {
            a[i] = (a[i] * iz) % self.modulo;
        }
        a
    }
}

fn mod_inv(x: i64, m: i64) -> i64 {
    mod_pow(x, m - 2, m)
}

fn mod_pow(x: i64, mut e: i64, m: i64) -> i64 {
    let mut cur = x;
    let mut result = 1;
    while e > 0 {
        if e & 1 == 1 {
            result = (result * cur) % m;
        }
        e >>= 1;
        cur = (cur * cur) % m;
    }
    result
}

fn primitive_root(m: i64) -> i64 {
    if m == 2 {
        return 1;
    };
    if m == 167772161 {
        return 3;
    };
    if m == 469762049 {
        return 3;
    };
    if m == 754974721 {
        return 11;
    };
    if m == 998244353 {
        return 3;
    };
    let mut divs = [0; 20];
    divs[0] = 2;
    let mut cnt = 1;
    let mut x = (m - 1) / 2;
    while x % 2 == 0 {
        x /= 2
    }

    let mut i = 3;
    while i * i <= x {
        if x % i == 0 {
            divs[cnt] = i;
            cnt += 1;
            while x % i == 0 {
                x /= i;
            }
        }
        i += 2;
    }
    if x > 1 {
        divs[cnt] = x;
        cnt += 1;
    }

    for g in 2.. {
        let mut ok = true;
        for i in 0..cnt {
            if mod_pow(g, (m - 1) / divs[i], m) == 1 {
                ok = false;
                break;
            }
        }
        if ok {
            return g;
        }
    }
    unreachable!()
}

pub struct IO<R, W: std::io::Write>(R, std::io::BufWriter<W>);

impl<R: std::io::Read, W: std::io::Write> IO<R, W> {
    pub fn new(r: R, w: W) -> Self {
        Self(r, std::io::BufWriter::new(w))
    }
    pub fn write<S: ToString>(&mut self, s: S) {
        use std::io::Write;
        self.1.write_all(s.to_string().as_bytes()).unwrap();
    }
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .0
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r' || b == b'\t')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r' && b != b'\t')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}