常用素数及其原根
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
typedef long long LL;
const LL mod = 998244353;
int N, M;
LL a[100005], b[100005], c[100005], g;
LL qpower(LL, LL);
LL inline inv(LL x) { return qpower(x, mod - 2); }
void NTT(LL *, int, int);
int main() {
std::cin >> N >> M;
for (int i = 0; i < N; ++i) std::cin >> a[i];
for (int i = 0; i < M; ++i) std::cin >> b[i];
int sz = 1;
g = 3;
while (sz < N + M) sz <<= 1;
NTT(a, sz, 1);
NTT(b, sz, 1);
for (int i = 0; i < sz; ++i)
c[i] = a[i] * b[i] % mod;
NTT(c, sz, -1);
for (int i = 0; i < N + M - 1; ++i)
std::cout << c[i] << " ";
return 0;
}
LL qpower(LL x, LL y) {
LL res = 1;
while (y) {
if (y & 1) (res *= x) %= mod;
(x *= x) %= mod;
y >>= 1;
}
return res;
}
void NTT(LL *arr, int size, int type) {
int rev[100005];
rev[0] = 0;
for (int i = 1; i < size; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (size >> 1) : 0);
for (int i = 0; i < size; ++i)
if (rev[i] > i) std::swap(arr[i], arr[rev[i]]);
for (int len = 2; len <= size; len <<= 1) {
LL wn = qpower(g, (mod - 1) / len);
if (type == -1) wn = inv(wn);
for (int i = 0; i < size; i += len) {
LL w = 1;
for (int j = 0; j < (len >> 1); ++j, w = w * wn % mod) {
LL tmp1 = arr[i + j], tmp2 = arr[i + (len >> 1) + j] * w % mod;
arr[i + j] = tmp1 + tmp2;
arr[i + j + (len >> 1)] = tmp1 - tmp2;
if (arr[i + j] >= mod) arr[i + j] -= mod;
if (arr[i + j + (len >> 1)] < 0) arr[i + j + (len >> 1)] += mod;
}
}
}
if (type == -1) {
LL t = inv(size);
for (int i = 0; i < size; ++i)
arr[i] = arr[i] * t % mod;
}
}
//Rhein_E