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: Wrong Answer)

//  ____            _                  _                       _       _
// |  _ \ _   _ ___| |_    ___ _ __   | |_ ___ _ __ ___  _ __ | | __ _| |_ ___
// | |_) | | | / __| __|  / __| '_ \  | __/ _ \ '_ ` _ \| '_ \| |/ _` | __/ _ \
// |  _ <| |_| \__ \ |_  | (__| |_) | | ||  __/ | | | | | |_) | | (_| | ||  __/
// |_| \_\\__,_|___/\__|  \___| .__/___\__\___|_| |_| |_| .__/|_|\__,_|\__\___|
//                            |_| |_____|               |_|

//https://github.com/manta1130/Competitive_Programming_Template_Rust

mod fft{

type ValueType = isize;
const delta: f64 = 0.01;

///数列の畳み込みを計算する
///
///浮動小数点計算のため誤差に注意
pub fn convolve(a: &Vec<ValueType>, b: &Vec<ValueType>) -> Vec<ValueType> {
    let mut ar = vec![];
    let mut ai = vec![];
    for &i in a.iter().rev() {
        ar.push(i as f64);
        ai.push(0.0);
    }

    let mut br = vec![];
    let mut bi = vec![];
    for &i in b.iter().rev() {
        br.push(i as f64);
        bi.push(0.0);
    }
    let r_len = a.len() + b.len() - 1;
    for _ in 0..r_len - a.len() {
        ar.push(0.0);
        ai.push(0.0);
    }
    for _ in 0..r_len - b.len() {
        br.push(0.0);
        bi.push(0.0);
    }

    let mut rr = vec![];
    let mut ri = vec![];

    fft(&mut ar, &mut ai, false);
    fft(&mut br, &mut bi, false);

    for i in 0..ar.len() {
        let r = ar[i] * br[i] - ai[i] * bi[i];
        let j = ar[i] * bi[i] + ai[i] * br[i];
        rr.push(r);
        ri.push(j);
    }

    fft(&mut rr, &mut ri, true);

    rr.iter()
        .rev()
        .map(|&x| (x + delta) as ValueType)
        .collect::<Vec<_>>()
}

///数列の畳み込みを計算する(mod演算付き)
///
///浮動小数点計算のため誤差に注意
pub fn convolve_mod(a: &Vec<ValueType>, b: &Vec<ValueType>, p: isize) -> Vec<ValueType> {
    let mut a1 = vec![];
    let mut a2 = vec![];
    for &x in a {
        let upper = (x & !((1 << 16) - 1)) >> 15;
        let lower = x & ((1 << 16) - 1);
        a1.push(upper);
        a2.push(lower);
    }
    let mut b1 = vec![];
    let mut b2 = vec![];
    for &x in b {
        let upper = (x & !((1 << 16) - 1)) >> 15;
        let lower = x & ((1 << 16) - 1);
        b1.push(upper);
        b2.push(lower);
    }

    let mut x = convolve(&mut a1, &mut b1);
    for i in x.iter_mut() {
        *i %= p;
    }
    let mut z = convolve(&mut a2, &mut b2);
    for i in z.iter_mut() {
        *i %= p;
    }
    let y = convolve(
        &a1.iter().zip(&a2).map(|(&a, &b)| a + b).collect::<Vec<_>>(),
        &b1.iter().zip(&b2).map(|(&a, &b)| a + b).collect::<Vec<_>>(),
    );
    let xz = x.iter().zip(&z).map(|(&a, &b)| a + b).collect::<Vec<_>>();
    let y = y
        .iter()
        .zip(&xz)
        .map(|(&a, &b)| (a - b) % p)
        .collect::<Vec<_>>();

    let mut res = vec![];
    for i in 0..x.len() {
        res.push(((x[i] << 30) + (y[i] << 15) + z[i]) % p);
    }
    res
}

///FFTを計算する
///
/// ar:実部
///
/// ai:虚部
///
/// inv:逆変換時はtrue
///
/// arとaiの要素数は同一である必要がある。
///
pub fn fft(ar: &mut Vec<f64>, ai: &mut Vec<f64>, inv: bool) {
    if ar.len() != ai.len() {
        panic!("ar.len()!=ai.len()");
    }

    let mut n = ar.len();
    //配列の要素数が2のべき乗でない場合は調整する
    while ar.len().count_ones() != 1 {
        n += 1;
        ar.push(0.0);
        ai.push(0.0);
    }

    let (mut wr, mut wi, mut xr, mut xi): (f64, f64, f64, f64);
    let w = if inv { -1.0 } else { 1.0 } * 2.0 * std::f64::consts::PI / (n as f64);

    let mut i = 0;
    for j in 1..n - 1 {
        let mut k = n >> 1;
        loop {
            i ^= k;
            if k <= i {
                break;
            }
            k >>= 1
        }

        if j < i {
            xr = ar[j];
            xi = ai[j];
            ar[j] = ar[i];
            ai[j] = ai[i];
            ar[i] = xr;
            ai[i] = xi;
        }
    }

    let mut mh = 1;
    loop {
        let m = mh << 1;
        if m > n {
            break;
        }
        let mut irev = 0;

        i = 0;
        while i < n {
            wr = (w * irev as f64).cos();
            wi = (w * irev as f64).sin();
            let mut k = n >> 2;
            loop {
                irev ^= k;
                if k <= irev {
                    break;
                }
                k >>= 1;
            }

            for j in i..mh + i {
                k = j + mh;
                xr = ar[j] - ar[k];
                xi = ai[j] - ai[k];
                ar[j] += ar[k];
                ai[j] += ai[k];
                ar[k] = wr * xr - wi * xi;
                ai[k] = wr * xi + wi * xr;
            }

            i += m;
        }
        mh = m;
    }
    if inv {
        for i in ar.iter_mut() {
            *i /= n as f64;
        }
        for i in ai.iter_mut() {
            *i /= n as f64;
        }
    }
}

}

#[allow(unused_imports)]
use proconio::{
    fastout, input,
    marker::{Bytes, Chars, Isize1, Usize1},
};

use fft::*;

#[fastout]
fn main() {
    input! {
        n:usize,
        m:usize,
        a:[isize;n],
        b:[isize;m],
    }
    let ans = convolve_mod(&a, &b, 998244353);

    for i in ans.iter().take(n + m - 1) {
        print!("{} ", i);
    }
    println!("");
}