#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <vector>
#include <queue>
#include <algorithm>
#include <map>
#include <climits>
#include <set>
#include <cmath>
#include <numeric>
#include <cfloat>
#include <iomanip>
using namespace std;
int a[50][50];
const long long MOD = 998244353;
vector <int> edges[50];
long long fact[51];
bool done[50];
long long dfs(int cur){
  done[cur] = true;
  int ret = 1;
  for(int i = 0; i < edges[cur].size(); i++){
    if(!done[edges[cur][i]]){
      ret += dfs(edges[cur][i]);
    }
  }
  return ret;
}

int main(){
  int N;
  int K;
  cin >> N >> K;
  for(int i = 0; i < N; i++){
    for(int j = 0; j < N; j++){
      cin >> a[i][j];
    }
  }

  fact[0] = 1;
  for(int i = 0; i < N; i++){
    fact[i + 1] = (fact[i] * (i + 1)) % MOD;
  }

  if(N == 1){
    cout << 1 << endl;
    return 0;
  }
  
  for(int i = 0; i < N - 1; i++){
    for(int j = i + 1; j < N; j++){
      bool swappable = true;
      for(int k = 0; k < N; k++){
        if(a[i][k] + a[j][k] > K){
          swappable = false;
          break;
        }
      }

      if(swappable){
        edges[i].push_back(j);
        edges[j].push_back(i);
      }
    }
  }

  long long ans = 1;
  for(int i = 0; i < N; i++){
    if(!done[i]){
      ans = (ans * fact[dfs(i)]) % MOD;
    }
  }

  for(int i = 0; i < N; i++){
    edges[i].clear();
    done[i] = false;
  }

  for(int i = 0; i < N - 1; i++){
    for(int j = i + 1; j < N; j++){
      bool swappable = true;
      for(int k = 0; k < N; k++){
        if(a[k][i] + a[k][j] > K){
          swappable = false;
          break;
        }
      }

      if(swappable){
        edges[i].push_back(j);
        edges[j].push_back(i);
      }
    }
  }

  for(int i = 0; i < N; i++){
    if(!done[i]){
      ans = (ans * fact[dfs(i)]) % MOD;
    }
  }

  cout << ans << endl;
  return 0;
}

#include<bits/stdc++.h>
//#include<atcoder/all>

using namespace std;
//using namespace atcoder;

using ll = long long;
using Graph = vector<vector<int>>;

#define rep(i,m,n) for(int (i)=(m);(i)<(n);++(i))
#define rrep(i,m,n) for(int (i)=(n)-1;(i)>=(m);--(i))
#define all(x) (x).begin(),(x).end()
#define out(y,x,h,w) (y)<0||(x)<0||(y)>=(h)||(x)>=(w)

constexpr ll INF = (ll)1e9;
constexpr ll mod = 998244353;
constexpr double PI = 3.1415926535897932;

template<class T>inline bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
template<class T>inline bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}
inline void init() {
    cin.tie(nullptr); cout.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(15);
}

struct mint {
    ll x; // typedef long long ll;
    mint(ll x = 0) :x((x% mod + mod) % mod) {}
    mint operator-() const { return mint(-x); }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod - a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t >> 1);
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }

    // for prime mod
    mint inv() const {
        return pow(mod - 2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res /= a;
    }
};
struct UnionFind {
	vector<int>d;

	UnionFind(int N) :d(N, -1) {}

	int find(int x) {
		if (d[x] < 0)return x;
		return d[x] = find(d[x]);
	}
	bool unite(int x, int y) {
		x = find(x); y = find(y);
		if (x == y)return false;
		if (d[x] > d[y])swap(x, y);
		d[x] += d[y];
		d[y] = x;
		return true;
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
	int size(int x) {
		return -d[find(x)];
	}
};

mint func(int a) {
    if (a == 0)return 1;
    return (mint)a * func(a - 1);
}

int main() {
    init();

	int N, K; cin >> N >> K;
	vector<vector<int>>mat(N, vector<int>(N));
	rep(i, 0, N)rep(j, 0, N)cin >> mat[i][j];
    UnionFind uf1(N), uf2(N);
	rep(i, 0, N) {
        rep(j, i + 1, N) {
            bool a = true, b = true;
			rep(k, 0, N) {
                if (mat[k][i] + mat[k][j] > K)a = false;
                if (mat[i][k] + mat[j][k] > K)b = false;
			}
            if (a)uf1.unite(i, j);
            if (b)uf2.unite(i, j);
		}
	}
    mint a = 1, b = 1;
    rep(i, 0, N) {
        if (uf1.d[i] < 0)a *= func(-uf1.d[i]);
        if (uf2.d[i] < 0)b *= func(-uf2.d[i]);
    }
    mint ans = a * b;
    cout << ans.x << "\n";

    return 0;
}