#include using namespace std; template struct Modint { int x; Modint() : x(0) {} Modint(int64_t y) { if (y >= 0) x = y % MOD; else x = (y % MOD + MOD) % MOD; } Modint &operator+=(const Modint &p) { x += p.x; if (x >= MOD) x -= MOD; return *this; } Modint &operator-=(const Modint &p) { x -= p.x; if (x < 0) x += MOD; return *this; } Modint &operator*=(const Modint &p) { x = int(1LL * x * p.x % MOD); return *this; } Modint &operator/=(const Modint &p) { *this *= p.inverse(); return *this; } Modint &operator%=(const Modint &p) { assert(p.x == 0); return *this; } Modint operator-() const { return Modint(-x); } Modint &operator++() { x++; if (x == MOD) x = 0; return *this; } Modint &operator--() { if (x == 0) x = MOD; x--; return *this; } Modint operator++(int) { Modint result = *this; ++*this; return result; } Modint operator--(int) { Modint result = *this; --*this; return result; } friend Modint operator+(const Modint &lhs, const Modint &rhs) { return Modint(lhs) += rhs; } friend Modint operator-(const Modint &lhs, const Modint &rhs) { return Modint(lhs) -= rhs; } friend Modint operator*(const Modint &lhs, const Modint &rhs) { return Modint(lhs) *= rhs; } friend Modint operator/(const Modint &lhs, const Modint &rhs) { return Modint(lhs) /= rhs; } friend Modint operator%(const Modint &lhs, const Modint &rhs) { assert(rhs.x == 0); return Modint(lhs); } bool operator==(const Modint &p) const { return x == p.x; } bool operator!=(const Modint &p) const { return x != p.x; } bool operator<(const Modint &rhs) const { return x < rhs.x; } bool operator<=(const Modint &rhs) const { return x <= rhs.x; } bool operator>(const Modint &rhs) const { return x > rhs.x; } bool operator>=(const Modint &rhs) const { return x >= rhs.x; } Modint inverse() const { int a = x, b = MOD, u = 1, v = 0, t; while (b > 0) { t = a / b; a -= t * b; u -= t * v; std::swap(a, b); std::swap(u, v); } return Modint(u); } Modint pow(int64_t k) const { Modint ret(1); Modint y(x); while (k > 0) { if (k & 1) ret *= y; y *= y; k >>= 1; } return ret; } friend std::ostream &operator<<(std::ostream &os, const Modint &p) { return os << p.x; } friend std::istream &operator>>(std::istream &is, Modint &p) { int64_t y; is >> y; p = Modint(y); return (is); } static int get_mod() { return MOD; } }; struct Arbitrary_Modint { int x; static int MOD; static void set_mod(int mod) { MOD = mod; } Arbitrary_Modint() : x(0) {} Arbitrary_Modint(int64_t y) { if (y >= 0) x = y % MOD; else x = (y % MOD + MOD) % MOD; } Arbitrary_Modint &operator+=(const Arbitrary_Modint &p) { x += p.x; if (x >= MOD) x -= MOD; return *this; } Arbitrary_Modint &operator-=(const Arbitrary_Modint &p) { x -= p.x; if (x < 0) x += MOD; return *this; } Arbitrary_Modint &operator*=(const Arbitrary_Modint &p) { x = int(1LL * x * p.x % MOD); return *this; } Arbitrary_Modint &operator/=(const Arbitrary_Modint &p) { *this *= p.inverse(); return *this; } Arbitrary_Modint &operator%=(const Arbitrary_Modint &p) { assert(p.x == 0); return *this; } Arbitrary_Modint operator-() const { return Arbitrary_Modint(-x); } Arbitrary_Modint &operator++() { x++; if (x == MOD) x = 0; return *this; } Arbitrary_Modint &operator--() { if (x == 0) x = MOD; x--; return *this; } Arbitrary_Modint operator++(int) { Arbitrary_Modint result = *this; ++*this; return result; } Arbitrary_Modint operator--(int) { Arbitrary_Modint result = *this; --*this; return result; } friend Arbitrary_Modint operator+(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) += rhs; } friend Arbitrary_Modint operator-(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) -= rhs; } friend Arbitrary_Modint operator*(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) *= rhs; } friend Arbitrary_Modint operator/(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { return Arbitrary_Modint(lhs) /= rhs; } friend Arbitrary_Modint operator%(const Arbitrary_Modint &lhs, const Arbitrary_Modint &rhs) { assert(rhs.x == 0); return Arbitrary_Modint(lhs); } bool operator==(const Arbitrary_Modint &p) const { return x == p.x; } bool operator!=(const Arbitrary_Modint &p) const { return x != p.x; } bool operator<(const Arbitrary_Modint &rhs) { return x < rhs.x; } bool operator<=(const Arbitrary_Modint &rhs) { return x <= rhs.x; } bool operator>(const Arbitrary_Modint &rhs) { return x > rhs.x; } bool operator>=(const Arbitrary_Modint &rhs) { return x >= rhs.x; } Arbitrary_Modint inverse() const { int a = x, b = MOD, u = 1, v = 0, t; while (b > 0) { t = a / b; a -= t * b; u -= t * v; std::swap(a, b); std::swap(u, v); } return Arbitrary_Modint(u); } Arbitrary_Modint pow(int64_t k) const { Arbitrary_Modint ret(1); Arbitrary_Modint y(x); while (k > 0) { if (k & 1) ret *= y; y *= y; k >>= 1; } return ret; } friend std::ostream &operator<<(std::ostream &os, const Arbitrary_Modint &p) { return os << p.x; } friend std::istream &operator>>(std::istream &is, Arbitrary_Modint &p) { int64_t y; is >> y; p = Arbitrary_Modint(y); return (is); } static int get_mod() { return MOD; } }; int Arbitrary_Modint::MOD = 998244353; using modint9 = Modint<998244353>; using modint1 = Modint<1000000007>; using modint = Arbitrary_Modint; template struct lazy_segtree { public: explicit lazy_segtree(const std::vector &v) : _n(int(v.size())) { size = 1; log = 0; while (size < _n) { log++; size <<= 1; } d = std::vector(2 * size, e()); lz = std::vector(size, id()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; for (int i = size - 1; i >= 1; i--) update(i); } explicit lazy_segtree(int n) : lazy_segtree(std::vector(n, e())) {} S prod(int l, int r) { if (l == r) return e(); l += size; r += size; for (int i = log; i >= 1; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } S sml = e(), smr = e(); while (l < r) { if (l & 1) sml = op(sml, d[l++]); if (r & 1) smr = op(d[--r], smr); l >>= 1; r >>= 1; } return op(sml, smr); } S get(int x) { return prod(x, x + 1); } S all_prod() { return d[1]; } void apply(int l, int r, F f) { if (l == r) return; l += size; r += size; for (int i = log; i >= 1; i--) { if (((l >> i) << i) != l) push(l >> i); if (((r >> i) << i) != r) push((r - 1) >> i); } { int l2 = l, r2 = r; while (l < r) { if (l & 1) all_apply(l++, f); if (r & 1) all_apply(--r, f); l >>= 1; r >>= 1; } l = l2; r = r2; } for (int i = 1; i <= log; i++) { if (((l >> i) << i) != l) update(l >> i); if (((r >> i) << i) != r) update((r - 1) >> i); } } private: int _n, size, log; std::vector d; std::vector lz; void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); } void all_apply(int k, F f) { d[k] = mapping(f, d[k]); if (k < size) lz[k] = composition(f, lz[k]); } void push(int k) { all_apply(2 * k, lz[k]); all_apply(2 * k + 1, lz[k]); lz[k] = id(); } }; namespace PerTreeRangeAddRangeMin { using S = int; S op(S l, S r) { return l < r ? l : r; } S e() { return 1 << 30; } using F = int; S mapping(F f, S x) { return f + x; } F composition(F f, F g) { return f + g; } F id() { return 0; } using SEG = lazy_segtree; } // namespace PerTreeRangeAddRangeMin struct PermutationTree { enum NodeType { JOIN_ASC, JOIN_DESC, CUT, LEAF, NONE, }; struct Node { NodeType tp; int l, r; int x_min, x_max; std::vector child; int size() { return r - l; } }; int root; std::vector P; std::vector nodes; PermutationTree() : root(-1) {} PermutationTree(const std::vector &P) : root(-1), P(P) { assert(!P.empty()); build(); } private: void add_child(int par, int chi) { nodes[par].child.push_back(chi); nodes[par].l = std::min(nodes[par].l, nodes[chi].l); nodes[par].r = std::max(nodes[par].r, nodes[chi].r); nodes[par].x_min = std::min(nodes[par].x_min, nodes[chi].x_min); nodes[par].x_max = std::max(nodes[par].x_max, nodes[chi].x_max); } void build() { PerTreeRangeAddRangeMin::SEG seg((std::vector(P.size()))); std::stack hi, lo; hi.push(-1); lo.push(-1); std::stack st; for (int i = 0; i < int(P.size()); i++) { while (hi.size() >= 2 and P[i] > P[hi.top()]) { auto hi_fi = hi.top(); hi.pop(); auto hi_se = hi.empty() ? -1 : hi.top(); seg.apply(hi_se + 1, hi_fi + 1, P[i] - P[hi_fi]); } hi.push(i); while (lo.size() >= 2 and P[i] < P[lo.top()]) { auto lo_fi = lo.top(); lo.pop(); auto lo_se = lo.empty() ? -1 : lo.top(); seg.apply(lo_se + 1, lo_fi + 1, P[lo_fi] - P[i]); } lo.push(i); int h = nodes.size(); nodes.push_back({NodeType::LEAF, i, i + 1, P[i], P[i], std::vector()}); while (1) { NodeType join_tp = NodeType::NONE; if (!st.empty() and nodes[st.top()].x_max + 1 == nodes[h].x_min) { join_tp = NodeType::JOIN_ASC; } else if (!st.empty() and nodes[h].x_max + 1 == nodes[st.top()].x_min) { join_tp = NodeType::JOIN_DESC; } if (!st.empty() and join_tp != NodeType::NONE) { const Node &vtp = nodes[st.top()]; if (join_tp == vtp.tp) { add_child(st.top(), h); h = st.top(); st.pop(); } else { int j = st.top(); nodes.push_back( {join_tp, nodes[j].l, nodes[j].r, nodes[j].x_min, nodes[j].x_max, {j}}); st.pop(); add_child(nodes.size() - 1, h); h = nodes.size() - 1; } } else if (seg.prod(0, i + 1 - nodes[h].size()) == 0) { int l = nodes[h].l; int r = nodes[h].r; int x_max = nodes[h].x_max; int x_min = nodes[h].x_min; nodes.push_back({NodeType::CUT, l, r, x_min, x_max, {h}}); h = nodes.size() - 1; do { add_child(h, st.top()); st.pop(); } while (nodes[h].x_max - nodes[h].x_min + 1 != nodes[h].size()); std::reverse(nodes[h].child.begin(), nodes[h].child.end()); } else { break; } } st.push(h); seg.apply(0, i + 1, -1); } assert(st.size() == 1); root = st.top(); } }; using mint = modint9; void solve() { int n, k; cin >> n >> k; vector P(n); for (int i = 0; i < n; i++) { cin >> P[i]; P[i]--; } PermutationTree pt(P); vector> dp(n + 1, vector(k + 1, 0)); dp[0][0] = 1; auto dfs = [&](auto &&self, int pos) -> void { auto &u = pt.nodes[pos]; if (u.tp == PermutationTree::NodeType::LEAF or u.tp == PermutationTree::NodeType::CUT) { for (int i = 0; i < k; i++) { dp[u.r][i + 1] += dp[u.l][i]; } } vector add(k, 0); for (auto npos : u.child) { self(self, npos); auto &v = pt.nodes[npos]; if (u.tp == PermutationTree::NodeType::JOIN_ASC or u.tp == PermutationTree::NodeType::JOIN_DESC) { for (int i = 0; i < k; i++) { dp[v.r][i + 1] += add[i]; add[i] += dp[v.l][i]; } } } }; dfs(dfs, pt.root); for (int i = 1; i <= k; i++) { cout << dp[n][i] << endl; } } int main() { // cin.tie(0)->sync_with_stdio(0); int t; t = 1; // cin >> t; while (t--) solve(); return 0; }