#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define sz(x) ((int)x.size())
#define D if(1) // DEBUG
#define dominance true

template<int m>
struct mi { // modint
  int r;
  mi(int v=0): r(v) {}
  mi operator+(mi i) const { return r+i.r-(r+i.r>=m?m:0); }
  mi operator-(mi i) const { return r-i.r+(r-i.r<0?m:0); }
  mi operator*(mi i) const { return (1LL*r*i.r)%m; }
  mi operator^(ll k) const {
    mi t = 1;
    for(mi b = r; k; k /= 2, b = b * b)
      if(k & 1) t = t * b;
    return t;
  }
  mi operator/(mi i) const { return *this * (i ^ (m - 2)); }
  friend ostream& operator<<(ostream& os, mi i) {
    return os << i.r; }
};
const int mod = 998244353;

template<typename T>
struct M {
  #define rep(i, n) for(int i = 0; i < n; i++)
  vector<vector<T>> A;  int r, c;
  M(int n, int m): r(n), c(m), A(n, vector<T>(m)) {}
  vector<T>& operator[](int i) { return A[i]; }
  M operator*(M& B) {
    assert(c == B.r);  M C(r, B.c);
    rep(i, r) rep(j, B.c) rep(k, c)
      C[i][j] = C[i][j] + A[i][k] * B[k][j];
    return C;
  }
  M operator^(ll k) {
    M B = *this, R(r, c);
    rep(i, r) R[i][i] = 1;
    for(; k; k /= 2, B = B * B)
      if(k & 1) R = R * B;
    return R;
  }
  #undef rep
};

int dfa[26][50];
bool term[50];

void solve() {
  int n, m;
  cin >> n >> m;
  
  int t_size = 1;
  auto add_word =
    [&](const string& s) {
      int v = 0;
      for(char cc : s) {
        int c = cc - 'a';
        if(!dfa[c][v]) dfa[c][v] = t_size++;
        v = dfa[c][v];
      }
      term[v] = true;
    };

  for(int i = 0 ; i < n ; i++) {
    string s;
    cin >> s;
    add_word(s);
  }

  auto id = [&](int u, int v) { return u * t_size + v; };
  vector<vector<int>> adj(t_size * t_size, vector<int>(t_size * t_size));
  for(int u = 0 ; u < t_size ; u++) {
    for(int v = 0 ; v < t_size ; v++) {
      for(int c = 0 ; c < 26 ; c++) {
        auto [nu, nv] = tie(dfa[c][u], dfa[c][v]);
        if(nu && nv) {
          adj[id(u, v)][id(nu, nv)]++;
          if(term[nu]) adj[id(u, v)][id(0, nv)]++;
          if(term[nv]) adj[id(u, v)][id(nu, 0)]++;
          if(term[nu] && term[nv]) adj[id(u, v)][id(0, 0)]++;
        }
      }
    }
  }

  deque<int> q;
  q.pb(id(0, 0));
  vector<bool> vis(t_size * t_size);
  vis[id(0, 0)] = true;
  while(sz(q)) {
    int u = q.front();  q.pop_front();
    for(int v = 0 ; v < t_size * t_size ; v++)
      if(adj[u][v] && !vis[v]) {
        vis[v] = true;
        q.pb(v);
      }
  }
  
  // do we lose enough nodes from compressing? Maybe.
  set<int> nodes;
  for(int u = 0 ; u < t_size * t_size ; u++)
    if(vis[u])
      nodes.insert(u);
  
  map<int, int> mp;
  for(int x : nodes) mp[x] = sz(mp);

  M<mi<mod>> mat(sz(mp), sz(mp));
  for(int u = 0 ; u < t_size * t_size ; u++)
    for(int v = 0 ; v < t_size * t_size ; v++)
      if(vis[u] && vis[v] && adj[u][v])
        mat[mp[u]][mp[v]] = adj[u][v];
  
  mat = mat ^ ((ll) m);
  cout << mat[0][0] << '\n';
}

int main() {
  assert(dominance);
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.precision(20);
  solve();
  return 0;
}