(in-package :cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
  (sb-int:defconstant-eqx opt
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0))
    #'equal)
  #+swank (ql:quickload '(:cl-debug-print :fiveam) :silent t)
  #-swank (set-dispatch-macro-character
           #\# #\> (lambda (s c p) (declare (ignore c p)) `(values ,(read s nil nil t)))))
#+swank (set-dispatch-macro-character #\# #\> #'cl-debug-print:debug-print-reader)

(macrolet ((def-int (b)
             `(progn (deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))
                     (deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))))
           (defs (&rest bits) `(progn ,@(mapcar (lambda (b) `(def-int ,b)) bits))))
  (defs 2 4 7 8 15 16 31 32 62 63 64))

(defconstant +mod+ 998244353)

(defmacro dbg (&rest forms)
  #+swank (if (= (length forms) 1)
              `(format *error-output* "~A => ~A~%" ',(car forms) ,(car forms))
              `(format *error-output* "~A => ~A~%" ',forms `(,,@forms)))
  #-swank (declare (ignore forms)))

(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
  (let ((*read-default-float-format* 'double-float))
    (prog1 (princ obj stream) (terpri stream))))

;; BEGIN_INSERTED_CONTENTS
(defpackage :cp/tzcount
  (:use :cl)
  (:export #:tzcount))
(in-package :cp/tzcount)

(declaim (inline tzcount))
(defun tzcount (x)
  "Returns the number of trailing zero bits. Note that (TZCOUNT 0) = -1."
  (- (integer-length (logand x (- x))) 1))

;;;
;;; Fast Number Theoretic Transform
;;; Reference: https://github.com/ei1333/library/blob/master/math/fft/number-theoretic-transform-friendly-mod-int.cpp
;;;

(defpackage :cp/ntt
  (:use :cl :cp/tzcount)
  (:export #:+ntt-mod+ #:ntt-int #:ntt-vector #:ntt! #:inverse-ntt! #:ntt-convolve
           #:check-ntt-vector #:%mod-inverse #:%mod-power))
(in-package :cp/ntt)

(defconstant +ntt-mod+ 998244353)
(defconstant +ntt-root+ 3)
(deftype ntt-int () '(unsigned-byte 31))
(deftype ntt-vector () '(simple-array ntt-int (*)))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (assert (typep +ntt-mod+ 'ntt-int)))

(declaim (inline %mod-power))
(defun %mod-power (base exp)
  (declare (ntt-int base)
           ((integer 0 #.most-positive-fixnum) exp))
  (let ((res 1))
    (declare (ntt-int res))
    (loop while (> exp 0)
          when (oddp exp)
          do (setq res (mod (* res base) +ntt-mod+))
          do (setq base (mod (* base base) +ntt-mod+)
                   exp (ash exp -1)))
    res))

(declaim (inline %mod-inverse))
(defun %mod-inverse (x)
  (%mod-power x (- +ntt-mod+ 2)))

(defun check-ntt-vector (vector)
  (declare (optimize (speed 3))
           (vector vector))
  (let ((len (length vector)))
    (assert (zerop (logand len (- len 1)))) ;; power of two
    (check-type len ntt-int)))

(defun make-ntt-base ()
  (let* ((base-size (tzcount (- +ntt-mod+ 1)))
         (base (make-array base-size :element-type 'ntt-int))
         (inv-base (make-array base-size :element-type 'ntt-int)))
    (dotimes (i base-size)
      (setf (aref base i)
            (mod (- (%mod-power +ntt-root+ (ash (- +ntt-mod+ 1) (- (+ i 2)))))
                 +ntt-mod+)
            (aref inv-base i)
            (%mod-inverse (aref base i))))
    (values base inv-base)))

(defvar *ntt-base*)
(defvar *ntt-inv-base*)
(multiple-value-bind (base inv-base) (make-ntt-base)
  (setq *ntt-base* base)
  (setq *ntt-inv-base* inv-base))

(declaim (ftype (function * (values ntt-vector &optional)) ntt!))
(defun ntt! (vector)
  (declare (optimize (speed 3) (safety 0))
           (vector vector))
  (check-ntt-vector vector)
  (labels ((mod* (x y) (mod (* x y) +ntt-mod+))
           (mod+ (x y)
             (let ((res (+ x y)))
               (if (>= res +ntt-mod+)
                   (- res +ntt-mod+)
                   res)))
           (mod- (x y) (mod+ x (- +ntt-mod+ y))))
    (declare (inline mod* mod+ mod-))
    (let* ((vector (coerce vector 'ntt-vector))
           (len (length vector))
           (base *ntt-base*))
      (declare ((simple-array ntt-int (*)) vector base)
               (ntt-int len))
      (when (<= len 1)
        (return-from ntt! vector))
      (loop for m of-type ntt-int = (ash len -1) then (ash m -1)
            while (> m 0)
            for w of-type ntt-int = 1
            for k of-type ntt-int = 0
            do (loop for s of-type ntt-int from 0 below len by (* 2 m)
                     do (loop for i from s below (+ s m)
                              for j from (+ s m)
                              for x = (aref vector i)
                              for y = (mod* (aref vector j) w)
                              do (setf (aref vector i) (mod+ x y)
                                       (aref vector j) (mod- x y)))
                        (incf k)
                        (setq w (mod* w (aref base (tzcount k))))))
      vector)))

(defun inverse-ntt! (vector &optional inverse)
  (declare (optimize (speed 3) (safety 0))
           (vector vector))
  (check-ntt-vector vector)
  (labels ((mod* (x y)
             (declare (ntt-int x y))
             (mod (* x y) +ntt-mod+))
           (mod+ (x y)
             (declare (ntt-int x y))
             (let ((res (+ x y)))
               (if (>= res +ntt-mod+)
                   (- res +ntt-mod+)
                   res)))
           (mod- (x y)
             (declare (ntt-int x y))
             (mod+ x (- +ntt-mod+ y))))
    (declare (inline mod* mod+ mod-))
    (let* ((vector (coerce vector 'ntt-vector))
           (len (length vector))
           (base *ntt-inv-base*))
      (declare ((simple-array ntt-int (*)) vector base)
               (ntt-int len))
      (when (<= len 1)
        (return-from inverse-ntt! vector))
      (loop for m of-type ntt-int = 1 then (ash m 1)
            while (< m len)
            for w of-type ntt-int = 1
            for k of-type ntt-int = 0
            do (loop for s of-type ntt-int from 0 below len by (* 2 m)
                     do (loop for i from s below (+ s m)
                              for j from (+ s m)
                              for x = (aref vector i)
                              for y = (aref vector j)
                              do (setf (aref vector i) (mod+ x y)
                                       (aref vector j) (mod* (mod- x y) w)))
                        (incf k)
                        (setq w (mod* w (aref base (tzcount k))))))
      (when inverse
        (let ((inv-len (%mod-power len (- +ntt-mod+ 2))))
          (dotimes (i len)
            (setf (aref vector i) (mod* inv-len (aref vector i))))))
      vector)))

;; FIXME: Here I resort to SBCL's behaviour. Actually ADJUST-ARRAY isn't
;; guaranteed to preserve the given VECTOR.
(declaim (ftype (function * (values ntt-vector &optional)) %adjust-array))
(defun %adjust-array (vector length)
  (declare (vector vector))
  (let ((vector (coerce vector 'ntt-vector)))
    (if (= (length vector) length)
        (copy-seq vector)
        (adjust-array vector length :initial-element 0))))

;; Change %ADJUST-ARRAY to ADJUST-ARRAY when if what you want is a destructive
;; operation.
(declaim (ftype (function * (values ntt-vector &optional)) ntt-convolve))
(defun ntt-convolve (vector1 vector2)
  (declare (optimize (speed 3))
           (vector vector1 vector2))
  (let ((len1 (length vector1))
        (len2 (length vector2)))
    (when (or (zerop len1) (zerop len2))
      (return-from ntt-convolve (make-array 0 :element-type 'ntt-int)))
    (let* ((mul-len (max 0 (- (+ len1 len2) 1)))
           ;; power of two ceiling
           (required-len (ash 1 (integer-length (max 0 (- mul-len 1)))))
           (vector1 (ntt! (%adjust-array vector1 required-len)))
           (vector2 (ntt! (%adjust-array vector2 required-len))))
      (dotimes (i required-len)
        (setf (aref vector1 i)
              (mod (* (aref vector1 i) (aref vector2 i)) +ntt-mod+)))
      (adjust-array (inverse-ntt! vector1 t) mul-len))))

(defpackage :cp/read-fixnum
  (:use :cl)
  (:export #:read-fixnum))
(in-package :cp/read-fixnum)

(declaim (ftype (function * (values fixnum &optional)) read-fixnum))
(defun read-fixnum (&optional (in *standard-input*))
  "NOTE: cannot read -2^62"
  (declare #.cl-user::opt)
  (macrolet ((%read-byte ()
               `(the (unsigned-byte 8)
                     #+swank (char-code (read-char in nil #\Nul))
                     #-swank (sb-impl::ansi-stream-read-byte in nil #.(char-code #\Nul) nil))))
    (let* ((minus nil)
           (result (loop (let ((byte (%read-byte)))
                           (cond ((<= 48 byte 57)
                                  (return (- byte 48)))
                                 ((zerop byte) ; #\Nul
                                  (error "Read EOF or #\Nul."))
                                 ((= byte #.(char-code #\-))
                                  (setq minus t)))))))
      (declare ((integer 0 #.most-positive-fixnum) result))
      (loop
        (let* ((byte (%read-byte)))
          (if (<= 48 byte 57)
              (setq result (+ (- byte 48)
                              (* 10 (the (integer 0 #.(floor most-positive-fixnum 10))
                                         result))))
              (return (if minus (- result) result))))))))

;; BEGIN_USE_PACKAGE
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/read-fixnum :cl-user))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/ntt :cl-user))
(in-package :cl-user)

;;;
;;; Body
;;;

(defun main ()
  (let* ((n (read))
         (m (read))
         (as (make-array n :element-type 'ntt-int :initial-element 0))
         (bs (make-array m :element-type 'ntt-int :initial-element 0)))
    (dotimes (i n)
      (setf (aref as i) (read-fixnum)))
    (dotimes (i m)
      (setf (aref bs i) (read-fixnum)))
    (let ((cs (ntt-convolve as bs))
          (init t))
      (write-string
       (with-output-to-string (*standard-output* nil :element-type 'base-char)
         (dotimes (i (+ n m -1) (terpri))
           (if init
               (setq init nil)
               (write-char #\ ))
           (write (aref cs i))))))))

#-swank (main)

;;;
;;; Test and benchmark
;;;

#+swank
(defun get-clipbrd ()
  (with-output-to-string (out)
    #+os-windows (run-program "powershell.exe" '("-Command" "Get-Clipboard") :output out :search t)
    #+os-unix (run-program "xsel" '("-b" "-o") :output out :search t)))

#+swank (defparameter *this-pathname* (uiop:current-lisp-file-pathname))
#+swank (defparameter *dat-pathname* (uiop:merge-pathnames* "test.dat" *this-pathname*))

#+swank
(defun run (&optional thing (out *standard-output*))
  "THING := null | string | symbol | pathname

null: run #'MAIN using the text on clipboard as input.
string: run #'MAIN using the string as input.
symbol: alias of FIVEAM:RUN!.
pathname: run #'MAIN using the text file as input."
  (let* ((*standard-output* (or out (make-string-output-stream)))
         (res (etypecase thing
                (null
                 (with-input-from-string (*standard-input* (delete #\Return (get-clipbrd)))
                   (main)))
                (string
                 (with-input-from-string (*standard-input* (delete #\Return thing))
                   (main)))
                (symbol (5am:run! thing))
                (pathname
                 (with-open-file (*standard-input* thing)
                   (main))))))
    (if out res (get-output-stream-string *standard-output*))))

#+swank
(defun gen-dat ()
  (uiop:with-output-file (out *dat-pathname* :if-exists :supersede)
    (format out "")))

#+swank
(defun bench (&optional (out (make-broadcast-stream)))
  (time (run *dat-pathname* out)))

#-swank
(eval-when (:compile-toplevel)
  (when (and (boundp 'sb-c::*compiler-warning-count*)
             (> sb-c::*compiler-warning-count* 0))
    (sb-ext:quit :unix-status 1)))

;; To run: (5am:run! :sample)
#+swank
(it.bese.fiveam:test :sample
  (it.bese.fiveam:is
   (equal "5 16 34 60 70 70 59 36
"
          (run "4 5
1 2 3 4
5 6 7 8 9
" nil)))
  (it.bese.fiveam:is
   (equal "871938225
"
          (run "1 1
10000000
10000000
" nil))))


Measured memory_bytes: 62232