from typing import List, Tuple class lazy_segtree: """It is the data structure for the pair of a monoid (S, op) and a set F of S to S mappings that satisfies the following properties. > F contains the identity map id, where the identity map is the map that satisfies id(x) = x for all x in S. > F is closed under composition, i.e., `composition(f, g)` is in F for all `f`, `g` in F. > `f(op(x, y)) = op(f(x), f(y))` holds for all `f` in F and `x`, `y` in S. Given an array of length n, it processes the following queries in O(log n) time (see Appendix in the document of AC Library for further details). > Acting the map f in F (cf. x = f(x)) on all the elements of an interval > Calculating the product of the elements of an interval For simplicity, in this document, we assume that the oracles `op`, `e`, `mapping`, `composition`, and `id_` work in constant time. If these oracles work in O(T) time, each time complexity appear in this document is multipled by O(T). """ __slots__ = ["op", "e", "mapping", "composition", "id_", "n", "log", "size", "d", "lz"] def __init__(self, n_or_list, op, e, mapping, composition, id_): """The following should be defined. > The binary operation `op(a, b)` > The function `e()` that returns the identity element > The function `mapping(f, x)` that returns f(x) > The function `composition(f, g)` that returns f composed with g > The function `id_()` that returns the identity map For example, for Range Multiplication Range Sum Query, the definitions are as follows. ```python seg = lazy_segtree(10, lambda a, b: a+b, lambda: 0, lambda f, x: f*x, lambda f, g: f*g, lambda: 1) ``` > If `n_or_list` is an integer, it creates an array `a` of length `n_or_list`. All the elements are initialized to `e()`. > If `n_or_list` is a list, it creates an array `a` of length `len(n_or_list)`, initialized to `n_or_list`. > Otherwise, it raises `TypeError`. Constraints ----------- > 0 <= n <= 10 ** 8 Complexity ---------- > O(n) """ self.op = op self.e = e self.mapping = mapping self.composition = composition self.id_ = id_ if isinstance(n_or_list, int): self.n = n_or_list self.log = (self.n - 1).bit_length() self.size = 1 << self.log self.d = [self.e() for _ in range(self.size * 2)] self.lz = [self.id_() for _ in range(self.size)] elif isinstance(n_or_list, list): self.n = len(n_or_list) self.log = (self.n - 1).bit_length() self.size = 1 << self.log self.d = [self.e() for _ in range(self.size)] + n_or_list + \ [self.e() for _ in range(self.size - self.n)] for i in range(self.size - 1, 0, -1): self.d[i] = self.op(self.d[2*i], self.d[2*i+1]) self.lz = [self.id_() for _ in range(self.size)] else: raise TypeError( f"The argument 'n_or_list' must be an integer or a list, not {type(n_or_list).__name__}") def set(self, p, x): """It assigns x to `a[p]`. Constraints ----------- > 0 <= p < n Complexity ---------- > O(log n) """ # assert 0 <= p < self.n p += self.size for i in range(self.log, 0, -1): self._push(p >> i) self.d[p] = x for i in range(1, self.log + 1): self._update(p >> i) def get(self, p): """It returns `a[p]`. Constraints ----------- > 0 <= p < n Complexity ---------- > O(log n) """ # assert 0 <= p < self.n p += self.size for i in range(self.log, 0, -1): self._push(p >> i) return self.d[p] def prod(self, l, r): """It returns `op(a[l], ..., a[r - 1])`, assuming the properties of the monoid. It returns `e()` if l = r. Constraints ----------- > 0 <= l <= r <= n Complexity ---------- > O(log n) """ # assert 0 <= l <= r <= self.n if l == r: return self.e() l += self.size r += self.size indices = [] l0 = (l // (l & -l)) // 2 r0 = (r // (r & -r) - 1) // 2 while l0 != r0: if l0 < r0: indices.append(r0) r0 //= 2 else: indices.append(l0) l0 //= 2 while r0: indices.append(r0) r0 //= 2 for index in reversed(indices): self._push(index) sml = self.e() smr = self.e() while l < r: if l % 2: sml = self.op(sml, self.d[l]) l += 1 if r % 2: r -= 1 smr = self.op(self.d[r], smr) l //= 2 r //= 2 return self.op(sml, smr) def all_prod(self): """It returns `op(a[0], ..., a[n - 1])`, assuming the properties of the monoid. It returns `e()` if n = 0. Complexity ---------- > O(1) """ return self.d[1] def point_apply(self, p, f): """It applies `a[p] = f(a[p])`. Constraints ----------- > 0 <= p < n Complexity ---------- > O(log n) """ # assert 0 <= p <= self.n p += self.size for i in range(self.log, 0, -1): self._push(p >> i) self.d[p] = self.mapping(f, self.d[p]) for i in range(1, self.log + 1): self._update(p >> i) def apply(self, l, r, f): """It applies `a[i] = f(a[i])` for all `i` with `l <= i < r`. Constraints ----------- > 0 <= l <= r <= n Complexity ---------- > O(log n) """ # assert 0 <= l <= r <= self.n if l == r: return l += self.size r += self.size indices = [] l0 = (l // (l & -l)) // 2 r0 = (r // (r & -r) - 1) // 2 while l0 != r0: if l0 < r0: indices.append(r0) r0 //= 2 else: indices.append(l0) l0 //= 2 while r0: indices.append(r0) r0 //= 2 for index in reversed(indices): self._push(index) while l < r: if l % 2: self._all_apply(l, f) l += 1 if r % 2: r -= 1 self._all_apply(r, f) l //= 2 r //= 2 for index in indices: self._update(index) def max_right(self, l, g): """It returns an index `r` that satisfies both of the following. > `r == l` or `g(op(a[l], a[l + 1], ..., a[r - 1])) == True` > `r == n` or `g(op(a[l], a[l + 1], ..., a[r])) == False` If `g` is monotone, this is the maximum `r` that satisfies `g(op(a[l], a[l + 1], ..., a[r - 1])) == True`. Constraints ----------- > if `g` is called with the same argument, it returns the same value, i.e., `g` has no side effect. > `g(e()) == True` > 0 <= l <= n Complexity ---------- > O(log n) """ # assert 0 <= l <= self.n # assert g(self.e()) if l == self.n: return self.n l += self.size for i in range(self.log, 0, -1): self._push(l >> i) sm = self.e() while True: while l % 2 == 0: l //= 2 if not g(self.op(sm, self.d[l])): while l < self.size: self._push(l) l *= 2 if g(self.op(sm, self.d[l])): sm = self.op(sm, self.d[l]) l += 1 return l - self.size sm = self.op(sm, self.d[l]) l += 1 if l == l & -l: break return self.n def min_left(self, r, g): """It returns an index `l` that satisfies both of the following. > `l == r` or `g(op(a[l], a[l + 1], ..., a[r - 1])) == True` > `l == 0` or `g(op(a[l - 1], a[l], ..., a[r - 1])) == False` If `g` is monotone, this is the minimum `l` that satisfies `g(op(a[l], a[l + 1], ..., a[r - 1])) == True`. Constraints ----------- > if `g` is called with the same argument, it returns the same value, i.e., `g` has no side effect. > `g(e()) == True` > 0 <= r <= n Complexity ---------- > O(log n) """ # assert 0 <= r <= self.n # assert g(self.e()) if r == 0: return 0 r += self.size for i in range(self.log, 0, -1): self._push((r - 1) >> i) sm = self.e() while True: r -= 1 while (r > 1 and r % 2): r //= 2 if not g(self.op(self.d[r], sm)): while r < self.size: self._push(r) r = 2 * r + 1 if g(self.op(self.d[r], sm)): sm = self.op(self.d[r], sm) r -= 1 return r + 1 - self.size sm = self.op(self.d[r], sm) if r == r & -r: break return 0 def _update(self, k): self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1]) def _all_apply(self, k, f): self.d[k] = self.mapping(f, self.d[k]) if k < self.size: self.lz[k] = self.composition(f, self.lz[k]) def _push(self, k): self._all_apply(2 * k, self.lz[k]) self._all_apply(2 * k + 1, self.lz[k]) self.lz[k] = self.id_() class permutation_tree: def __init__(self, vec: List[int]) -> None: self.vec = vec self.build() def get_range(self, x: Tuple[int, int], y: Tuple[int, int]) -> Tuple[int, int]: return (min(x[0], y[0]), max(x[1], y[1])) def adj(self, i: int, j: int) -> bool: return self.range_[i][1] == self.range_[j][0] def length(self, i: int) -> int: return self.range_[i][1] - self.range_[i][0] def add_edge(self, p: int, c: int) -> None: self.parent[c] = p self.children[p].append(c) def build(self) -> None: max_stack = [-1] min_stack = [-1] nodes = [] self.sz = n = len(self.vec) self.parent = [-1] * (n * 2) self.children = [[] for _ in range(n * 2)] self.range_ = [(0, 0)] * (n * 2) self.span = [(0, 0)] * (n * 2) self.typ = [0] * (n * 2) seg = lazy_segtree([0] * (n * 2), min, lambda: 1 << 30, lambda f, x: f + x, lambda f, g: f + g, lambda: 0) for i in range(n): while max_stack[-1] != -1 and self.vec[max_stack[-1]] < self.vec[i]: tmp = max_stack.pop() seg.apply(max_stack[-1] + 1, tmp + 1, self.vec[i] - self.vec[tmp]) max_stack.append(i) while min_stack[-1] != -1 and self.vec[min_stack[-1]] > self.vec[i]: tmp = min_stack.pop() seg.apply(min_stack[-1] + 1, tmp + 1, self.vec[tmp] - self.vec[i]) min_stack.append(i) self.range_[i] = (self.vec[i], self.vec[i] + 1) self.span[i] = (i, i + 1) cur = i while True: if nodes and (self.adj(nodes[-1], cur) or self.adj(cur, nodes[-1])): if (self.adj(nodes[-1], cur) and self.typ[nodes[-1]] == 2) or (self.adj(cur, nodes[-1]) and self.typ[nodes[-1]] == 1): self.add_edge(nodes[-1], cur) self.range_[ nodes[-1]] = self.get_range(self.range_[nodes[-1]], self.range_[cur]) self.span[nodes[-1]] = self.get_range( self.span[nodes[-1]], self.span[cur]) cur = nodes.pop() else: self.add_edge(self.sz, nodes[-1]) self.add_edge(self.sz, cur) self.typ[self.sz] = 2 if self.adj( nodes[-1], cur) else 1 self.range_[self.sz] = self.get_range( self.range_[nodes[-1]], self.range_[cur]) self.span[self.sz] = self.get_range( self.span[nodes[-1]], self.span[cur]) cur = self.sz self.sz += 1 nodes.pop() elif i + 1 - self.length(cur) and seg.prod(0, i + 1 - self.length(cur)) == 0: len_ = self.length(cur) rng = self.range_[cur] sp = self.span[cur] self.add_edge(self.sz, cur) while True: len_ += self.length(nodes[-1]) rng = self.get_range(rng, self.range_[nodes[-1]]) sp = self.get_range(sp, self.span[nodes[-1]]) self.add_edge(self.sz, nodes[-1]) nodes.pop() if rng[1] - rng[0] == len_: break self.children[self.sz].reverse() self.range_[self.sz] = rng self.span[self.sz] = sp cur = self.sz self.sz += 1 else: break nodes.append(cur) seg.apply(0, i + 1, -1) self.shrink() def shrink(self) -> None: self.parent = self.parent[:self.sz] self.children = self.children[:self.sz] self.range_ = self.range_[:self.sz] self.span = self.span[:self.sz] self.typ = self.typ[:self.sz] MOD = 998244353 N, K = map(int, input().split()) Ps = list(map(int, input().split())) def add(f, g): if len(f) < len(g): f, g = g, f ans = f.copy() for i, gi in enumerate(g): ans[i] += gi ans[i] %= MOD return ans[:K+1] def multiply(f, g): ans = [0] * (len(f) + len(g) - 1) for i, fi in enumerate(f): for j, gj in enumerate(g): ans[i + j] += fi * gj ans[i + j] %= MOD return ans[:K+1] perm_tree = permutation_tree(Ps) dp = [[] for _ in range(perm_tree.sz)] root = perm_tree.parent.index(-1) # print(root) stack = [~root, root] while stack: i = stack.pop() if i >= 0: for ni in perm_tree.children[i]: stack.append(~ni) stack.append(ni) else: i = ~i if 0 <= i < N: dp[i] = [0, 1] continue t = perm_tree.typ[i] cs = perm_tree.children[i] if t: csum = [[1]] ans = [1] for j, c in enumerate(cs): ans = multiply(ans, dp[c]) if j >= 1: ans = add(ans, [0] + csum[j-1]) csum.append(add(csum[-1], ans)) dp[i] = ans else: t = [1] for c in cs: t = multiply(t, dp[c]) t = add(t, [0, 1]) dp[i] = t ans = dp[root] while len(ans) < K + 1: ans.append(0) print(*ans[1:], sep='\n')