//https://l...content-available-to-author-only...j.ac/p/108
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;

#define pb push_back
#define ff first
#define ss second

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pld;

const int INF = 1e9;
const ll LLINF = 1e18;
const int MOD = 1e9 + 7;

template<class K> using sset =  tree<K, null_type, less<K>, rb_tree_tag, tree_order_statistics_node_update>;

inline ll ceil0(ll a, ll b) {
    return a / b + ((a ^ b) > 0 && a % b);
}

void setIO() {
    ios_base::sync_with_stdio(0); cin.tie(0);
}

const double PI = acos(-1);
typedef complex<ld> cint;

//Returns a complex number in the form of e^2*PI*k*i/n (i is an imaginary number)
cint root(int n, int k){
    return exp(cint(0, 2*PI*k/n));
}

//Returns the bitwise reverse of x using only the first mx bits
int rev(int x, int mx){
    int ret = 0;
    for(int i = 0; i <= mx; i++){
        if(x & (1 << i)) ret |= 1 << (mx - i);
    }
    return ret;
}

/**
 * Finds the Discrete Fourier Transform (DFT) of a polynomial using the
 * Fast Fourier Transform (FTT) method in O(n log n) time complexity.
 * 
 * Definitions:
 * 
 *  root(n, k) = e^(2*PI*i*k/n), where i is an imaginary number
 *  X = {x_1, x_2, x_3, ..., x_n}
 *  Y = {y_1, y_2, y_3, ..., y_n}
 *  F(x) = {x_1, x_2 * x, x_3 * x^2, ..., x_n * x^(n - 1)}
 * 
 *  DFT(X) = Y, defined as follows
 * 
 *      y_1 = F(root(n, 0))
 *      y_2 = F(root(n, 1))
 *      y_3 = F(root(n, 2))
 *         ...
 *      y_n = F(root(n, n - 1))
 * 
 * But how can we calculate Y, when DFT(X) = Y?
 *
 * Solution: 
 *  First, we see that we can split F(x) into even and odd parts, lets call them E(x), and O(x)
 * 
 *      O(x) = x_1 + x_3 * x + x_5 * x^2 ... x_(n - 1) * x^(n/2 - 1)
 *      E(x) = x_2 + x_4 * x + x_6 * x^2 ... x_n * x^(n/2 - 1)
 * 
 *  Then, F(x) becomes
 * 
 *      F(x) = O(x^2) + x * E(x^2)
 * 
 *  Since y_i = F(root(n, i - 1)), y_i becomes
 * 
 *      y_i = O(root(n, i - 1)^2) + root(n, i - 1) * E(root(n, i - 1)^2)
 * 
 *  Simplifying further, this becomes
 *  
 *      y0_i = O(root(n/2, i - 1)^2) = O(root(n, i - 1))
 *      y1_i = E(root(n/2, i - 1)^2) = E(root(n, i - 1))
 *      y_i = y0_i + root(n, i)*y1_i, i < n/2
 *      y_(n/2 + i) = y0_i + root(n, n/2 + i)*y1_i, n/2 <= i
 * 
 *  From here, we can find Y recursively. Since every split halves the n, and every merge takes O(n) complexity,
 *  amortized time complexity is O(n log n) 
 *  
 *  To calculate invDFT, it is the same as calculating DFT with only a few changes. Simply negate k when computing
 *  root(n, k), as well as dividing the final answer by n. This can be proven by using inverse matrices.
 * 
 * @param v The polynomial to perfom FFT on. The size of v should be a power of 2
 * @param sign Tndicates whether or not the function computes the 
 *             DFT if sign is 1 or invDFT if sign is -1.
 */
void fft(vector<cint> &v, int sign){
    int n = v.size(), lg = log2(n) - 1;
    cint tmp[n];  
    /**
     * swaps each position with its bitwise inverse. 
     * This step is needed to ensure correct ordering for the iterative implementation,
     * as some of the even and odd indices are swapped every iteration.
     */
    for(int i = 0; i < n; i++){
        if(i < rev(i, lg)) swap(v[i], v[rev(i, lg)]);
    }
    for(int i = 2; i <= n; i *= 2){
        //compute each segment of length i
        for(int j = 0; j < n; j += i){
            for(int k = 0; k < i/2; k++){
                //computes the left half of the segment using the formula described above
                tmp[k] = v[j + k] + root(i, sign*k)*v[j + i/2 + k];
                //computes the right half of the segment using the formula described above
                tmp[i/2 + k] = v[j + k] + root(i, sign*(i/2 + k))*v[j + i/2 + k];
            }
            //updates the actual values to the new values
            for(int k = 0; k < i; k++) v[j + k] = tmp[k];
        }
    }
    //If we are computing invDFT, we must divide every value by n
    if(sign == -1) for(cint &i : v) i /= n;
}

/**
 * Multiplies two polynomials using Discrete Fourier Transform (DFT) in O(n log n) time complexity.
 * 
 * Definitions:
 *  X = {x_1, x_2, x_3, ..., x_n}
 *  Y = {y_1, y_2, y_3, ..., y_n}
 * 
 *  DFT(X) = Y
 *  invDFT(Y) = X
 *  invDFT(DFT(X)) = X
 * 
 *  X * Y = the product of polynomials X and Y
 *  DFT(X) * DFT(Y) = {x_1 * y_1, x_2 * y_2, x_3 * y_3, ..., x_n * y_n}
 *  DFT(X * Y) = DFT(X) * DFT(Y)
 * 
 * Solution:
 *  Given two vectors A and B, lets define their product vector as ANS = A * B
 *  Then, using the distributive property, we can see that
 * 
 *      DFT(A * B) = DFT(A) * DFT(B)
 *      DFT(ANS) = DFT(A) * DFT(B)
 * 
 *  Applying invDFT to both sides, we get
 * 
 *      ANS = invDFT(DFT(A) * DFT(B))
 * 
 *  Performing DFT(A) * DFT(B) is much simpler than A * B, and can be done in O(n) time complexity
 *  We can calculate DFT and invDFT in O(n log n) time complexity, giving us a total complexity of O(n log n)
 * 
 * @param a the first polynomial
 * @param b the second polynomial
 * @return returns the polynomial a * b
 */
vector<ll> mult(const vector<ll> &a, const vector<ll> &b){
    //resizes the answer to a power of 2
    int n = 1;
    while(n < a.size() + b.size()) n *= 2;
    //constructs two copies of polynomials a and b, but using complex numbers instead
    vector<cint> aa(a.begin(), a.end()), bb(b.begin(), b.end());
    //resize the polynomials to have a size with a power of 2
    aa.resize(n), bb.resize(n);
    //computes DFT(a) and DFT(b)
    fft(aa, 1), fft(bb, 1);
    //sets a = DFT(a) * DFT(b) as described above
    for(int i = 0; i < n; i++) aa[i] *= bb[i];
    //returns a to a polynomial by setting a = invDFT(a)
    fft(aa, -1);
    //extracts the answer from the final polynomial. The values must be rounded due to double precision
    vector<ll> ret(n);
    for(int i = 0; i < n; i++){
        ret[i] = round(aa[i].real());
    }
    return ret;
}

int main(){
    setIO();
    int n, m;
    cin >> n >> m;
    n++, m++;
    vector<ll> v1(n), v2(m);
    for(int i = 0; i < n; i++) cin >> v1[i];
    for(int i = 0; i < m; i++) cin >> v2[i];
    vector<ll> ans = mult(v1, v2);
    //for(auto i : ans) cout << i << endl;
    for(int i = 0; i < n + m - 1; i++) cout << ans[i] << " ";
    cout << endl;
}