description: A subarray of array a from index l to the index r is the array [a_l, a_{l+1}, ..., a_{r}]. The number of occurrences of the array b in the array a is the number of subarrays of a such that they are equal to b.
  
  You are given n arrays A_1, A_2, ..., A_n; the elements of these arrays are integers from 1 to k. You have to build an array a consisting of m integers from 1 to k in such a way that, for every given subarray A_i, the number of occurrences of A_i in the array a is not less than the number of occurrences of each non-empty subarray of A_i in a. Note that if A_i doesn't occur in a, and no subarray of A_i occurs in a, this condition is still met for A_i.
  
  Your task is to calculate the number of different arrays a you can build, and print it modulo 998244353.
  
  Input
  
  The first line contains three integers n, m and k (1 ≤ n, m, k ≤ 3 ⋅ 10^5) — the number of the given arrays, the desired length of the array a, and the upper bound on the values in the arrays.
  
  Then n lines follow. The i-th line represents the array A_i. The first integer in the i-th line is c_i (1 ≤ c_i ≤ m) — the number of elements in A_i; then, c_i integers from 1 to k follow — the elements of the array A_i.
  
  Additional constraint on the input: ∑_{i=1}^n c_i ≤ 3 ⋅ 10^5; i. e., the number of elements in the given arrays in total does not exceed 3 ⋅ 10^5.
  
  Output
  
  Print one integer — the number of different arrays a you can build, taken modulo 998244353.
  
  Examples
  
  Input
  
  
  2 4 3
  2 1 2
  1 3
  
  
  Output
  
  
  5
  
  
  Input
  
  
  2 4 3
  2 1 2
  3 3 2 1
  
  
  Output
  
  
  0
  
  
  Input
  
  
  1 42 1337
  2 13 31
  
  
  Output
  
  
  721234447
solution: #include <bits/stdc++.h>
  const long long mod = 998244353, gen = 3;
  const long long inv2 = (mod + 1) / 2;
  const int maxn = 6E+5 + 5;
  namespace IObuf {
  const int LEN = 1 << 20;
  char ibuf[LEN + 5], *p1 = ibuf, *p2 = ibuf;
  char obuf[LEN + 5], *p3 = obuf;
  inline char get() {
    return p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, LEN, stdin), p1 == p2)
               ? EOF
               : *p1++;
    return getchar();
  }
  inline long long getll(char c = get(), long long x = 0, long long op = 1) {
    while (c < '0' || c > '9') c == '-' && (op = -op), c = get();
    while (c >= '0' && c <= '9') x = x * 10 + c - 48, c = get();
    return x * op;
  }
  inline char *flush() {
    fwrite(obuf, 1, p3 - obuf, stdout);
    return p3 = obuf;
  }
  inline void put(char c) {
    p3 == obuf + LEN &&flush();
    *p3++ = c;
    return;
    putchar(c);
  }
  char s[20];
  int t = 0;
  inline void putll(long long x, char suf = ' ') {
    if (!x)
      put('0');
    else {
      while (x) s[++t] = x % 10 + 48, x /= 10;
      while (t) put(s[t--]);
    }
    put(suf);
  }
  }  // namespace IObuf
  using IObuf::getll;
  using IObuf::putll;
  inline long long fsp(long long a, long long b, long long res = 1) {
    for (a %= mod; b; a = a * a % mod, b >>= 1) b & 1 ? res = res * a % mod : 0;
    return res;
  }
  namespace Math {
  int L = -1;
  long long _Fac[maxn << 2], _Inv[maxn << 2], _inv[maxn << 2];
  inline void pre(int l) {
    if (L == -1) {
      _Fac[0] = _Fac[1] = 1;
      _Inv[0] = _Inv[1] = 1;
      _inv[1] = 1, L = 1;
      if (l <= L) return;
    }
    for (int i = L + 1; i <= l; ++i) {
      _inv[i] = _inv[mod % i] * (mod - mod / i) % mod;
      _Fac[i] = _Fac[i - 1] * i % mod;
      _Inv[i] = _Inv[i - 1] * _inv[i] % mod;
    }
    L = l;
  }
  inline long long Fac(long long n) {
    if (L < n) pre(n);
    return _Fac[n];
  }
  inline long long Inv(long long n) {
    if (L < n) pre(n);
    return _Inv[n];
  }
  inline long long inv(long long n) {
    if (L < n) pre(n);
    return _inv[n];
  }
  inline long long binom(int n, int k) {
    if (k < 0 || n < k) return 0;
    return Fac(n) * Inv(k) % mod * Inv(n - k) % mod;
  }
  }  // namespace Math
  namespace Cipolla {
  long long imgn;
  struct complex {
    long long re, im;
    inline complex(long long _r = 0, long long _i = 0) : re(_r), im(_i) {}
    inline complex operator*(const complex &d) const {
      return complex((re * d.re + im * d.im % mod * imgn) % mod,
                     (re * d.im + im * d.re) % mod);
    }
  };
  inline complex mod_fsp(complex a, long long b, complex res = 1) {
    for (b %= mod - 1; b; a = a * a, b >>= 1)
      if (b & 1) res = res * a;
    return res;
  }
  std::mt19937_64 rnd(time(0));
  inline long long solve(long long x) {
    if (mod == 2 || !x) return x;
    long long a = 0;
    while (true) {
      a = rnd() % mod;
      if (fsp(mod + a * a - x, mod - 1 >> 1) == mod - 1) break;
    }
    imgn = (a * a - x + mod) % mod;
    long long ans = mod_fsp(complex(a, 1), mod + 1 >> 1).re;
    return std::min(ans, mod - ans);
  }
  }  // namespace Cipolla
  namespace Poly {
  struct poly {
    std::vector<long long> f;
    inline poly(long long v = 0) : f(1) { f[0] = v; }
    inline poly(const std::vector<long long> &_f) : f(_f) {}
    inline long long operator[](int p) const { return f[p]; }
    inline long long &operator[](int p) { return f[p]; }
    inline int deg() const { return f.size() - 1; }
    inline void redeg(int d) { f.resize(d + 1); }
    inline poly slice(int d) const {
      if (d < f.size())
        return std::vector<long long>(f.begin(), f.begin() + d + 1);
      std::vector<long long> res(f);
      return res.resize(d + 1), res;
    }
    inline void print(int d) const {
      for (int i = 0; i <= d && i < f.size(); ++i) putll(f[i]);
      for (int i = f.size(); i <= d; ++i) putll(0);
      IObuf::put('\n');
    }
    inline long long calc(long long x) const {
      long long res = 0, tmp = 1;
      for (int i = 0; i <= deg(); ++i) {
        res = (res + f[i] * tmp) % mod;
        tmp = tmp * x % mod;
      }
      return res;
    }
    inline poly operator+(const poly &P) const {
      std::vector<long long> res(std::max(deg(), P.deg()) + 1);
      for (int i = std::min(deg(), P.deg()); i >= 0; --i)
        (res[i] = f[i] + P[i]) >= mod ? res[i] -= mod : 0;
      for (int i = std::min(deg(), P.deg()) + 1; i < res.size(); ++i)
        res[i] = i <= deg() ? f[i] : P[i];
      return res;
    }
    inline poly operator-() const {
      poly res(f);
      for (int i = 0; i < f.size(); ++i) res[i] ? res[i] = mod - res[i] : 0;
      return res;
    }
    inline poly operator-(const poly &P) const { return operator+(-P); }
    inline poly operator<<(int d) const {
      poly res;
      res.redeg(d + deg());
      for (int i = 0; i <= deg(); ++i) res[i + d] = f[i];
      return res;
    }
    inline poly operator>>(int d) const {
      if (d > deg()) return poly(0);
      return std::vector<long long>(f.begin() + d, f.end());
    }
    inline poly operator*(const long long v) const {
      poly res(f);
      for (int i = 0; i <= deg(); ++i) res[i] = res[i] * v % mod;
      return res;
    }
    inline poly operator*(const poly &P) const;
    inline poly operator/(const poly &P) const;
    inline poly operator%(const poly &P) const;
    inline poly mul(const poly &P) const;
    inline poly intg(long long C) const;
    inline poly der() const;
    inline poly inv() const;
    inline poly quo(const poly &P) const;
    inline void divln(poly &res, int bit, int l, int r) const;
    inline poly ln() const;
    inline void divexp(poly &res, int bit, int l, int r) const;
    inline poly exp() const;
    inline poly pow(long long k) const;
    inline poly sqrt() const;
  };
  int Len = -1, rev[maxn * 4];
  unsigned long long rt[maxn * 4];
  inline void NTTpre(int bit) {
    if (Len >= bit) return;
    for (int i = Len + 1; i <= bit; ++i) {
      long long stp = fsp(gen, mod - 1 >> i);
      rt[1 << i] = 1;
      for (int j = (1 << i) + 1; j < (1 << i + 1); ++j)
        rt[j] = rt[j - 1] * stp % mod;
    }
    Len = bit;
  }
  unsigned long long tmp[maxn << 2];
  inline void NTT(poly &f, int bit, int op) {
    NTTpre(bit);
    int N = 1 << bit;
    if (f.deg() < N - 1) f.redeg(N - 1);
    for (int i = 0; i < N; ++i) {
      rev[i] = (rev[i >> 1] >> 1 | (i & 1) << bit - 1);
      tmp[i] = f[rev[i]] + (f[rev[i]] >> 31 & mod);
    }
    for (int len = 1; len < N; len <<= 1) {
      for (int i = 0; i < N; i += len << 1) {
        for (int k = i, x = len << 1; k < i + len; ++k, ++x) {
          long long g = tmp[k], h = tmp[k + len] * rt[x] % mod;
          tmp[k] = g + h, tmp[k + len] = mod + g - h;
        }
      }
    }
    for (int i = 0; i < N; ++i) f[i] = tmp[i] % mod;
    if (op == -1) {
      reverse(f.f.begin() + 1, f.f.begin() + N);
      long long invN = fsp(N, mod - 2);
      for (int i = 0; i < N; ++i) f[i] = f[i] * invN % mod;
    }
  }
  bool __WayToDeg = 0;
  inline poly poly::operator*(const poly &P) const {
    if (std::max(deg(), P.deg()) <= 128) {
      poly res;
      res.redeg(deg() + P.deg());
      for (int i = 0; i <= deg(); ++i)
        for (int j = 0; j <= P.deg(); ++j) (res[i + j] += f[i] * P[j]) %= mod;
      if (!__WayToDeg) res.redeg(std::max(deg(), P.deg()));
      return res;
    }
    poly F(f), G = P;
    int bit = 0, N = 1;
    while (N <= F.deg() + G.deg()) ++bit, N <<= 1;
    NTT(F, bit, 1), NTT(G, bit, 1);
    for (int i = 0; i < N; ++i) F[i] = F[i] * G[i] % mod;
    NTT(F, bit, -1);
    if (!__WayToDeg)
      return F.slice(std::max(deg(), P.deg()));
    else
      return F.slice(deg() + P.deg());
  }
  inline poly poly::operator/(const poly &P) const {
    if (deg() < P.deg()) return 0;
    poly g = std::vector<long long>(f.rbegin(), f.rend()),
         h = std::vector<long long>(P.f.rbegin(), P.f.rend());
    poly res = g.slice(deg() - P.deg()).quo(h.slice(deg() - P.deg()));
    res.redeg(deg() - P.deg()), reverse(res.f.begin(), res.f.end());
    return res;
  }
  inline poly poly::operator%(const poly &P) const {
    return operator-(operator/(P) * P).slice(P.deg() - 1);
  }
  inline poly poly::mul(const poly &P) const {
    __WayToDeg = 1;
    poly H = operator*(P);
    return __WayToDeg = 0, H;
  }
  inline poly poly::inv() const {
    poly g = fsp(f[0], mod - 2);
    for (int stp = 1; (1 << stp - 1) <= deg(); ++stp) {
      int N = 1 << stp;
      poly h = slice(N - 1), g0 = g;
      NTT(g, stp, 1), NTT(h, stp, 1);
      for (int i = 0; i < N; ++i) h[i] = h[i] * g[i] % mod;
      NTT(h, stp, -1);
      for (int i = 0; i < (N >> 1); ++i) h[i] = 0;
      NTT(h, stp, 1);
      for (int i = 0; i < N; ++i) g[i] = g[i] * h[i] % mod;
      NTT(g, stp, -1);
      for (int i = 0; i < (N >> 1); ++i) g[i] = 0;
      g = g0 - g;
    }
    return g.slice(deg());
  }
  inline poly poly::der() const {
    poly res;
    res.redeg(deg() - 1);
    for (int i = 1; i <= deg(); ++i) res[i - 1] = f[i] * i % mod;
    return res;
  }
  inline poly poly::intg(long long C = 0) const {
    poly res = C;
    res.redeg(deg() + 1);
    for (int i = 0; i <= deg(); ++i) res[i + 1] = f[i] * Math::inv(i + 1) % mod;
    return res;
  }
  inline poly poly::quo(const poly &P) const {
    if (deg() == 0) return fsp(P[0], mod - 2, f[0]);
    int bit = 0, N = 1;
    while (N <= P.deg()) ++bit, N <<= 1;
    poly g0 = P.slice((N >> 1) - 1).inv(), q0;
    poly h0 = slice((N >> 1) - 1);
    NTT(g0, bit, 1), NTT(h0, bit, 1), q0.redeg(N - 1);
    for (int i = 0; i < N; ++i) q0[i] = g0[i] * h0[i] % mod;
    NTT(q0, bit, -1), q0.redeg((N >> 1) - 1);
    poly q = q0, f0 = P;
    NTT(f0, bit, 1), NTT(q0, bit, 1);
    for (int i = 0; i < N; ++i) f0[i] = f0[i] * q0[i] % mod;
    NTT(f0, bit, -1), f0 = f0 - f;
    for (int i = 0; i < (N >> 1); ++i) f0[i] = 0;
    NTT(f0, bit, 1);
    for (int i = 0; i < N; ++i) f0[i] = f0[i] * g0[i] % mod;
    NTT(f0, bit, -1);
    for (int i = 0; i < (N >> 1); ++i) f0[i] = 0;
    return (q - f0).slice(deg());
  }
  const int logB = 4, B = 1 << logB;
  poly __divln_G[20][B];
  inline void poly::divln(poly &res, int bit, int l, int r) const {
    if (r - l <= 128) {
      r = std::min(r, deg() + 1);
      for (int i = l; i < r; ++i) {
        if (i == 0)
          res[i] = 0;
        else
          res[i] = (f[i] + mod - res[i] % mod * Math::inv(i) % mod) % mod;
        for (int j = i + 1; j < r; ++j)
          (res[j] += res[i] * f[j - i] % mod * i) %= mod;
      }
      return;
    }
    int dif = (r - l) / B, L = 0;
    poly w[B];
    while (L < B) {
      if (l + L * dif > deg()) break;
      w[L++].redeg(dif * 2 - 1);
    }
    for (int i = 0; i < L; ++i) {
      if (i != 0) {
        for (int j = 0; j < dif * 2; ++j) w[i][j] %= mod;
        Poly::NTT(w[i], bit - logB + 1, -1);
        for (int j = 0; j < dif; ++j) res[l + i * dif + j] += w[i][j + dif];
      }
      divln(res, bit - logB, l + i * dif, l + (i + 1) * dif);
      if (i != L - 1) {
        poly H;
        H.redeg(dif * 2 - 1);
        for (int j = 0; j < dif; ++j)
          H[j] = res[j + l + i * dif] * (j + l + i * dif) % mod;
        NTT(H, bit - logB + 1, 1);
        for (int j = i + 1; j < L; ++j)
          for (int k = 0; k < dif * 2; ++k)
            w[j][k] += H[k] * __divln_G[bit][j - i - 1][k];
      }
    }
  }
  inline poly poly::ln() const {
    poly res;
    int bit = 0, N = 1;
    while (N <= deg()) ++bit, N <<= 1;
    res.redeg(N - 1), NTTpre(bit);
    for (int b = bit; b >= logB; b -= logB) {
      int dif = 1 << (b - logB);
      for (int i = 0; i < B - 1; ++i) {
        if (dif * i > deg()) break;
        __divln_G[b][i].redeg(dif * 2 - 1);
        for (int j = 0; j < dif * 2 && i * dif + j <= deg(); ++j)
          __divln_G[b][i][j] = f[j + dif * i];
        NTT(__divln_G[b][i], b - logB + 1, 1);
      }
    }
    return divln(res, bit, 0, N), res;
  }
  poly __divexp_G[20][B];
  inline void poly::divexp(poly &res, int bit, int l, int r) const {
    if (r - l <= 128) {
      r = std::min(r, deg() + 1);
      for (int i = l; i < r; ++i) {
        if (i == 0)
          res[i] = 1;
        else
          res[i] = res[i] % mod * Math::inv(i) % mod;
        for (int j = i + 1; j < r; ++j)
          (res[j] += res[i] * f[j - i] % mod * (j - i)) %= mod;
      }
      return;
    }
    int mid = l + r >> 1, dif = (r - l) / B;
    int N = 1 << bit, L = 0;
    poly w[B];
    while (L < B) {
      if (l + L * dif > deg()) break;
      w[L++].redeg(dif * 2 - 1);
    }
    for (int i = 0; i < L; ++i) {
      if (i != 0) {
        for (int j = 0; j < dif * 2; ++j) w[i][j] %= mod;
        Poly::NTT(w[i], bit - logB + 1, -1);
        for (int j = 0; j < dif; ++j) res[l + i * dif + j] += w[i][j + dif];
      }
      divexp(res, bit - logB, l + i * dif, l + (i + 1) * dif);
      if (i != L - 1) {
        poly H;
        H.redeg(dif * 2 - 1);
        for (int j = 0; j < dif; ++j) H[j] = res[j + l + i * dif];
        NTT(H, bit - logB + 1, 1);
        for (int j = i + 1; j < L; ++j)
          for (int k = 0; k < dif * 2; ++k)
            w[j][k] += H[k] * __divexp_G[bit][j - i - 1][k];
      }
      if (L == i << 1)
        for (int j = i + 1; j < L; ++j)
          for (int k = 0; k < dif * 2; ++k) w[j].f[k] %= mod;
    }
  }
  inline poly poly::exp() const {
    poly res;
    int bit = 0, N = 1;
    while (N <= deg()) ++bit, N <<= 1;
    res.redeg(N - 1), NTTpre(bit);
    for (int b = bit; b >= logB; b -= logB) {
      int dif = 1 << (b - logB);
      for (int i = 0; i < B - 1; ++i) {
        if (dif * i > deg()) break;
        __divexp_G[b][i].redeg(dif * 2 - 1);
        for (int j = 0; j < dif * 2 && i * dif + j <= deg(); ++j)
          __divexp_G[b][i][j] = f[j + dif * i] * (j + dif * i) % mod;
        NTT(__divexp_G[b][i], b - logB + 1, 1);
      }
    }
    return divexp(res, bit, 0, N), res.slice(deg());
  }
  inline poly poly::pow(long long k) const { return (ln() * k).exp(); }
  inline poly poly::sqrt() const {
    poly g = Cipolla::solve(operator[](0)), h0 = fsp(g[0], mod - 2);
    for (int stp = 1; (1 << stp - 1) <= deg(); ++stp) {
      int N = 1 << stp;
      poly h = h0, g0 = g;
      NTT(g, stp - 1, 1);
      for (int i = 0; i < (N >> 1); ++i) g[i] = g[i] * g[i] % mod;
      NTT(g, stp - 1, -1), g = g - slice(N - 1);
      for (int i = 0; i < (N >> 1); ++i)
        (g[i + (N >> 1)] += g[i]) %= mod, g[i] = 0;
      g.redeg(N - 1), h.redeg(N - 1);
      NTT(g, stp, 1), NTT(h, stp, 1);
      for (int i = 0; i < N; ++i) g[i] = g[i] * h[i] % mod;
      NTT(g, stp, -1);
      for (int i = 0; i < (N >> 1); ++i) g[i] = 0;
      g = g0 - g * ((mod + 1) / 2);
      if ((1 << stp) <= deg()) {
        h = h0;
        poly f0 = slice(N - 1);
        h.redeg((N << 1) - 1), f0.redeg((N << 1) - 1);
        NTT(h, stp + 1, 1), NTT(f0, stp + 1, 1);
        for (int i = 0; i < (N << 1); ++i)
          h[i] = f0[i] * h[i] % mod * h[i] % mod * h[i] % mod;
        NTT(h, stp + 1, -1);
        h = (h - h0) * inv2;
        for (int i = 0; i < (N >> 1); ++i) h[i] = 0;
        h0 = h0 - h.slice(N - 1);
      }
    }
    return g.slice(deg());
  }
  }  // namespace Poly
  using Poly::poly;
  int n, m, k;
  std::vector<std::pair<int, int>> to[maxn];
  inline void Add(int u, int v, int w) { to[u].emplace_back(v, w); }
  inline void Adde(int u, int v, int w) { Add(u, v, w), Add(v, u, -w); }
  bool vis[maxn], flag;
  int E, dep[maxn];
  std::set<int> DEP;
  inline void DFS(int u, int d) {
    vis[u] = 1, dep[u] = d;
    if (u > n) {
      ++E;
      if (DEP.count(d)) flag = 0;
      DEP.insert(d);
    }
    for (auto e : to[u]) {
      if (!vis[e.first])
        DFS(e.first, d + e.second);
      else if (dep[e.first] != dep[u] + e.second)
        flag = 0;
    }
  }
  int main() {
    n = getll(), m = getll(), k = getll();
    for (int i = 1; i <= n; ++i) {
      int c = getll();
      for (int j = 1; j <= c; ++j) Adde(i, n + getll(), j);
    }
    std::vector<int> ele;
    for (int i = 1; i <= k; ++i)
      if (!vis[n + i]) {
        DEP.clear(), E = 0, flag = 1, DFS(n + i, 0);
        if (flag) ele.push_back(E);
      }
    poly F;
    F.redeg(std::max(k, m));
    for (int x : ele) ++F[x];
    putll((poly(1) - F).inv()[m]), IObuf::flush();
  }
  