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 C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace AtCoderLibraryCSharp.Examples
{
    public static class Program
    {
        public static void Main()
        {
            var NM = Console.ReadLine().Split(" ").Select(int.Parse).ToArray();
            var (N, M) = (NM[0], NM[1]);
            var A = Console.ReadLine().Split(" ").Select(long.Parse)
                .Select(x => new ModuloInteger(x)).ToArray();
            var B = Console.ReadLine().Split(" ").Select(long.Parse)
                .Select(x => new ModuloInteger(x)).ToArray();
            var c = Convolution.Execute(A, B);

            Console.WriteLine(string.Join(" ", c));
        }
    }
}

namespace AtCoderLibraryCSharp
{
    public static class Convolution
    {
        private static ModuloInteger[] _sumE;
        private static ModuloInteger[] _sumIe;
        private static int _primitiveRoot;

        public static IEnumerable<ModuloInteger> Execute(IEnumerable<ModuloInteger> a, IEnumerable<ModuloInteger> b)
        {
            var (a1, b1) = (a.ToArray(), b.ToArray());
            var (n, m) = (a1.Length, b1.Length);
            var ret = new ModuloInteger[n + m - 1];
            if (System.Math.Min(n, m) <= 60)
            {
                for (var i = 0; i < n; i++)
                for (var j = 0; j < m; j++)
                    ret[i + j] += a1[i] * b1[j];
                return ret;
            }

            var z = 1 << CeilPower2(n + m - 1);
            Array.Resize(ref a1, z);
            Array.Resize(ref b1, z);
            a1 = Butterfly(a1).ToArray();
            b1 = Butterfly(b1).ToArray();
            for (var i = 0; i < a1.Length; i++) a1[i] *= b1[i];
            ret = ButterflyInverse(a1).ToArray();
            Array.Resize(ref ret, n + m - 1);
            return ret.Select(x => x / z);
        }

        private static void Initialize()
        {
            if (_sumE != null && _sumIe != null) return;
            var m = ModuloInteger.Modulo;
            _primitiveRoot = PrimitiveRoot(m);
            _sumE = new ModuloInteger[30];
            _sumIe = new ModuloInteger[30];
            var es = new ModuloInteger[30];
            var ies = new ModuloInteger[30];
            var count2 = BitScanForward(m - 1);
            var e = new ModuloInteger(_primitiveRoot).Power((m - 1) >> count2);
            var ie = e.Inverse();
            for (var i = count2; i >= 2; i--)
            {
                es[i - 2] = e;
                ies[i - 2] = ie;
                e *= e;
                ie *= ie;
            }

            ModuloInteger now = 1;
            ModuloInteger inow = 1;
            for (var i = 0; i < count2 - 2; i++)
            {
                _sumE[i] = es[i] * now;
                _sumIe[i] = ies[i] * inow;
                now *= ies[i];
                inow *= es[i];
            }
        }

        private static IEnumerable<ModuloInteger> Butterfly(IEnumerable<ModuloInteger> items)
        {
            var ret = items.ToArray();
            var h = CeilPower2(ret.Length);
            Initialize();

            for (var ph = 1; ph <= h; ph++)
            {
                var w = 1 << (ph - 1);
                var p = 1 << (h - ph);
                ModuloInteger now = 1;
                for (var s = 0; s < w; s++)
                {
                    var offset = s << (h - ph + 1);
                    for (var i = 0; i < p; i++)
                    {
                        var l = ret[i + offset];
                        var r = ret[i + offset + p] * now;
                        ret[i + offset] = l + r;
                        ret[i + offset + p] = l - r;
                    }

                    now *= _sumE[BitScanForward(~s)];
                }
            }

            return ret;
        }

        private static IEnumerable<ModuloInteger> ButterflyInverse(IEnumerable<ModuloInteger> items)
        {
            var ret = items.ToArray();
            var h = CeilPower2(ret.Length);
            Initialize();

            for (var ph = h; ph >= 1; ph--)
            {
                var w = 1 << (ph - 1);
                var p = 1 << (h - ph);
                ModuloInteger inow = 1;
                for (var s = 0; s < w; s++)
                {
                    var offset = s << (h - ph + 1);
                    for (var i = 0; i < p; i++)
                    {
                        var l = ret[i + offset];
                        var r = ret[i + offset + p];
                        ret[i + offset] = l + r;
                        ret[i + offset + p] = (l - r) * inow;
                    }

                    inow *= _sumIe[BitScanForward(~s)];
                }
            }

            return ret;
        }

        private static int BitScanForward(long n)
        {
            if (n == 0) return 0;
            var x = 0;
            while ((n >> x & 1) == 0) x++;
            return x;
        }

        private static int CeilPower2(int n)
        {
            var x = 0;
            while ((1 << x) < n) x++;
            return x;
        }

        private static int PrimitiveRoot(long m)
        {
            if (_primitiveRoot != 0) return _primitiveRoot;
            switch (m)
            {
                case 2:
                    return _primitiveRoot = 1;
                case 167772161:
                case 469762049:
                case 998244353:
                    return _primitiveRoot = 3;
                case 754974721:
                    return _primitiveRoot = 11;
            }

            var divs = new long[20];
            divs[0] = 2;
            var count = 1;
            var x = (m - 1) / 2;
            while (x % 2 == 0) x /= 2;
            for (var i = 3; (long) i * i < x; i += 2)
            {
                if (x % i != 0) continue;
                divs[count++] = i;
                while (x % i == 0) x /= i;
            }

            if (x > 1) divs[count++] = x;
            for (var g = 2;; g++)
            {
                var ok = true;
                for (var i = 0; i < count && ok; i++)
                    if (Math.PowerMod(g, (m - 1) / divs[i], m) == 1)
                        ok = false;

                if (ok) return _primitiveRoot = g;
            }
        }
    }
}

namespace AtCoderLibraryCSharp
{
    public readonly struct ModuloInteger
    {
        public long Value { get; }
        public static long Modulo { get; private set; } = 998244353;

        public ModuloInteger(long data) => Value = (0 <= data ? data : data + Modulo) % Modulo;
        public static implicit operator long(ModuloInteger mint) => mint.Value;
        public static implicit operator int(ModuloInteger mint) => (int) mint.Value;
        public static implicit operator ModuloInteger(long val) => new ModuloInteger(val);
        public static implicit operator ModuloInteger(int val) => new ModuloInteger(val);
        public static ModuloInteger operator +(ModuloInteger a, ModuloInteger b) => a.Value + b.Value;
        public static ModuloInteger operator +(ModuloInteger a, long b) => a.Value + b;
        public static ModuloInteger operator +(ModuloInteger a, int b) => a.Value + b;
        public static ModuloInteger operator -(ModuloInteger a, ModuloInteger b) => a.Value - b.Value;
        public static ModuloInteger operator -(ModuloInteger a, long b) => a.Value - b;
        public static ModuloInteger operator -(ModuloInteger a, int b) => a.Value - b;
        public static ModuloInteger operator *(ModuloInteger a, ModuloInteger b) => a.Value * b.Value;
        public static ModuloInteger operator *(ModuloInteger a, long b) => a.Value * (b % Modulo);
        public static ModuloInteger operator *(ModuloInteger a, int b) => a.Value * (b % Modulo);
        public static ModuloInteger operator /(ModuloInteger a, ModuloInteger b) => a * b.Inverse();
        public static ModuloInteger operator /(ModuloInteger a, long b) => a.Value * Inverse(b);
        public static ModuloInteger operator /(ModuloInteger a, int b) => a.Value * Inverse(b);
        public static bool operator ==(ModuloInteger a, ModuloInteger b) => a.Value == b.Value;
        public static bool operator !=(ModuloInteger a, ModuloInteger b) => a.Value != b.Value;
        public bool Equals(ModuloInteger other) => Value == other.Value;
        public override bool Equals(object obj) => obj is ModuloInteger other && Equals(other);
        public override int GetHashCode() => Value.GetHashCode();
        public override string ToString() => Value.ToString();

        public ModuloInteger Inverse() => Inverse(Value);

        public static ModuloInteger Inverse(long a)
        {
            if (a == 0) return 0;
            var p = Modulo;
            var (x1, y1, x2, y2) = (1L, 0L, 0L, 1L);
            while (true)
            {
                if (p == 1) return (x2 % Modulo + Modulo) % Modulo;
                var div = a / p;
                x1 -= x2 * div;
                y1 -= y2 * div;
                a %= p;
                if (a == 1) return (x1 % Modulo + Modulo) % Modulo;
                div = p / a;
                x2 -= x1 * div;
                y2 -= y1 * div;
                p %= a;
            }
        }

        public ModuloInteger Power(long n) => Power(Value, n);

        public static ModuloInteger Power(ModuloInteger x, long n)
        {
            if (n < 0) throw new ArgumentException();
            var r = new ModuloInteger(1);
            while (n > 0)
            {
                if ((n & 1) > 0) r *= x;
                x *= x;
                n >>= 1;
            }

            return r;
        }

        public static void SetMod(long m) => Modulo = m;
        public static void SetMod998244353() => SetMod(998244353);
        public static void SetMod1000000007() => SetMod(1000000007);
    }
}

namespace AtCoderLibraryCSharp
{
    public static class Math
    {
        public static long PowerMod(long x, long n, long m)
        {
            if (n < 0) throw new ArgumentException(nameof(n));
            if (m < 1) throw new ArgumentException(nameof(m));
            if (m == 1) return 0;
            uint r = 1;
            var y = (uint) ((x < 0 ? x + m : x) % m);
            var um = (uint) m;
            while (n > 1)
            {
                if (n % 1 == 1) r = r * y % um;
                y = y * y % um;
                n >>= 1;
            }

            return r;
        }
    }
}