#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <utility>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <limits>
#define rep(i,n) for(int i = 0; i < n; ++i)
#define rep1(i,n) for(int i = 1; i <= n; ++i)
using namespace std;
template<class T>bool chmax(T &a, const T &b) { if(a < b){ a = b; return 1; } return 0; }
template<class T>bool chmin(T &a, const T &b) { if(a > b){ a = b; return 1; } return 0; }
template<class T> inline int  sz(T &a) { return a.size(); }
using ll = long long; using ld = long double;
using pi = pair<int,int>; using pl = pair<ll,ll>;
using vi = vector<int>; using vvi = vector<vi>;
using vl = vector<ll>; using vvl = vector<vl>;
const int inf = numeric_limits<int>::max();
const ll infll = numeric_limits<ll>::max();
// Modint
// modint<MOD> で宣言
template<ll MOD>
struct modint{
  ll x;
  ll mod = MOD;
  modint(ll x=0):x(x%MOD){}
  modint& operator+=(const modint a){
    if((x+=a.x)>=MOD) x-=MOD;
    return *this;
  }
  modint& operator-=(const modint a){
    if((x += MOD-a.x)>=MOD) x-=MOD;
    return *this;
  }
  modint& operator*=(const modint a){
    (x*=a.x)%=MOD;
    return *this;
  }
  modint operator+(const modint a) const{
    modint res(*this);
    return res+=a;
  }
  modint operator-(const modint a) const{
    modint res(*this);
    return res-=a;
  }
  modint operator*(const modint a) const{
    modint res(*this);
    return res*=a;
  }
  modint pow(ll t) const{
    if(!t) return 1;
    modint a = pow(t>>1);
    a*=a;
    if(t&1) a*=*this;
    return a;
  }
  
  //for prime mod
  modint inv() const{
    return pow(MOD-2);
  }
  modint& operator/=(const modint a){
    return (*this) *= a.inv();
  }
  modint operator/(const modint a) const{
    modint res(*this);
    return res/=a;
  }
};
using mint = modint<998244353>;

const int NMAX=1000010; // we can calculate nCk until n is equal to NMAX
mint fact[NMAX],infac[NMAX];
void Make_Fact(){
  fact[0]=fact[1]=1;
  for(int i=2;i<=NMAX-1;++i){
    fact[i]=fact[i-1]*(mint)i;
  }
}
void Make_InvFact(){
  infac[0]=infac[1]=1;
  for(int i=2;i<=NMAX-1;++i){
    infac[i]=infac[i-1]/(mint)i;	
  }
}
mint Comb(int n,int k){
  if(n<0||k<0||n-k<0) return 0;
  return fact[n]*infac[k]*infac[n-k];
}




struct UFT{
  vector<int> par;//親
  vector<int> rank;//木の深さ
  vector<int> size;//木の大きさ
  int n;
  
  UFT(int _n)
  {
    n = _n;
    par.resize(n);
    rank.assign(n,0);
    size.assign(n,1);
    rep(i,n){
      par[i] = i;
    }
  }
  
  //xの根を返す
  int find(int x)
  {
    if(par[x] == x) return x;
    else return par[x] = find(par[x]);
  }

  //x,yを併合
  void unite(int x,int y)
  {
    x = find(x);
    y = find(y);
    if(x == y) return;

    if(rank[x] < rank[y]){
      par[x] = y;
      size[y] += size[x];
    }
    else{
      par[y] = x;
      size[x] += size[y];
      if(rank[x] == rank[y]) rank[x]++;
    }
  }

  //x,yが同じグループにいるかどうかを返す
  bool same(int x,int y)
  {
    return find(x) == find(y);
  }

  //xの属する木のサイズを探す
  int usize(int x)
  {
    return size[find(x)];
  }
};



int main()
{
  int n,k; cin >> n >> k;
  vvi a(n, vi(n));
  rep(i,n) {
    rep(j,n) {
      cin >> a[i][j];
    }
  }

  Make_Fact();
  UFT uf(2*n);
  rep(i,n) {
    rep(j,n) {
      if(i >= j) continue;
      bool f = true;
      rep(l,n) {
	if(a[i][l] + a[j][l] > k) f =false;
      }
      if(f) uf.unite(i, j);
    }
  }

  rep(i,n) {
    rep(j,n) {
      if(i >= j) continue;
      bool f = true;
      rep(l,n) {
	if(a[l][i] + a[l][j] > k) f =false;
      }
      if(f) uf.unite(i+n, j+n);
    }
  }  

  mint res(1);
  rep(i,2*n) {
    if(uf.find(i) == i) {
      res *= fact[uf.usize(i)];
    }
  }

  cout << res.x << "\n";
  
  return 0;
}

#include <bits/stdc++.h>
using namespace std;
  
#define fst ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define int long long
#define tc int tt; cin >> tt; while(tt--) 
#define pb push_back
#define mp make_pair
#define ff first
#define ss second

const int N = 55, mod = 998244353;

map<int, vector<int> > m;
bool vis[N];
int f[N];

int dfs(int s) {
	vis[s] = 1;

	int sz = 0;
	for(auto x:m[s]) {
		if(!vis[x]) {
			sz += dfs(x);
		}
	}
	return 1 + sz;
}

int32_t main()
{
	fst
	#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout); 
	#endif

	int n, K;
	cin >> n >> K;
	int mat[n][n];
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) cin >> mat[i][j];
	}

	f[0] = f[1] = 1;
	for(int i=2;i<N;++i) f[i] = i*f[i-1], f[i] %= mod;

	for(int i=0;i<n;++i) {
		for(int j=i+1;j<n;++j) {
			bool ok = 1;
			for(int k=0;k<n;++k) {
				if(mat[i][k] + mat[j][k] > K) ok = 0;
			}

			if(ok) {
				m[i].pb(j);
				m[j].pb(i);
			}
		}
	}

	int ans = 1;
	for(int i=0;i<n;++i) {
		if(!vis[i]) {
			int sz = dfs(i);
			ans *= f[sz];
			ans %= mod;
		}
	}

	m.clear();
	memset(vis, 0, sizeof vis);

	for(int i=0;i<n;++i) {
		for(int j=i+1;j<n;++j) {
			bool ok = 1;
			for(int k=0;k<n;++k) {
				if(mat[k][i] + mat[k][j] > K) ok = 0;
			}

			if(ok) {
				m[i].pb(j);
				m[j].pb(i);
			}
		}
	}

	for(int i=0;i<n;++i) {
		if(!vis[i]) {
			int sz = dfs(i);
			ans *= f[sz];
			ans %= mod;
		}
	}

	cout << ans;
}