#include <bits/stdc++.h>

using namespace std;

const int MOD = 998244353;

class UnionFind {
private:
  vector<int> ps;

public:
  UnionFind(int n){
    ps.resize(n);
    for(int i = 0; i < n; i++){
      ps[i] = i;
    }
  }

  int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
  }

  void unite_sets(int i, int j){
    ps[find_set(i)] = find_set(j);
  }
};

const int MAXN = 60;

long long fat[MAXN * MAXN];

int main(){
  fat[0] = 1;
  for(int i = 1; i < MAXN*MAXN; i++){
    fat[i] = (i * fat[i-1])%MOD;
  }
  
  int N, K;
  while(scanf("%d%d", &N, &K) > 0){
    int a[N][N];
    for(int i = 0; i < N; i++){
      for(int j = 0; j < N; j++){
	scanf("%d", &a[i][j]);
      }
    }

    UnionFind uf(N);

    for(int x = 0; x < N; x++){
      for(int y = x+1; y < N; y++){
	bool test = true;
	for(int i = 0; i < N and test; i++){
	  test = a[x][i] + a[y][i] <= K;
	}
	if(test) uf.unite_sets(x, y);
      }
    }

    map<int,int> set_size;

    for(int i = 0; i < N; i++){
      set_size[uf.find_set(i)]++;
    }

    long long num_matrices = 1;

    for(auto s : set_size){
      num_matrices = (num_matrices * fat[s.second]) % MOD;
    }

    uf = UnionFind(N);
    
    for(int x = 0; x < N; x++){
      for(int y = x+1; y < N; y++){
	bool test = true;
	for(int i = 0; i < N and test; i++){
	  test = a[i][x] + a[i][y] <= K;
	}
	if(test) uf.unite_sets(x, y);
      }
    }

    set_size.clear();

    for(int i = 0; i < N; i++){
      set_size[uf.find_set(i)]++;
    }

    for(auto s : set_size){
      num_matrices = (num_matrices * fat[s.second]) % MOD;
    }

    printf("%lld\n", num_matrices);
  }
}

#include <bits/stdc++.h>
#define rep(i, n) for(int i = 0; i < (n); i++)
#define loop(i, a, n) for(int i = (a); i < (n); i++)
#define all(x) x.begin(), x.end()
#ifdef _DEBUG
#define disp(x) cout << #x << " : " << x << endl
#else
#define disp(x)
#endif
using namespace std;
using ll = int64_t;

const ll mod = 998244353;
struct mint {
    ll x;
    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 { return mint(*this) += a;}
    mint operator-(const mint a) const { return mint(*this) -= a;}
    mint operator*(const mint a) const { return mint(*this) *= a;}
    mint pow(ll t) const {
        if(!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if(t&1) a *= *this;
        return a;
    }

    ll val(){ return x; }

    // 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 { return mint(*this) /= a;}

    friend istream& operator>>(istream& is, mint& a) { return is >> a.x;}
    friend ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
};

struct UnionFind {
    ll n;
    vector<ll> siz, parent;
    map<ll,vector<ll>> group;
    UnionFind(ll n_) : n(n_), parent(n_), siz(n_, 1) {
        for(ll i = 0; i < n; i++) parent[i] = i;
    }
    ll root(ll x){
        if(parent[x] == x) return x;
        return parent[x] = root(parent[x]);
    }
    void unite(ll x,ll y){
        ll rx = root(x);
        ll ry = root(y);
        if(rx == ry) return;
        if(siz[rx] < siz[ry]) swap(rx, ry);
        siz[rx] += siz[ry];
        parent[ry] = rx;
    }
    bool same(ll x,ll y){
        ll rx = root(x);
        ll ry = root(y);
        return rx == ry;
    }
    void grouping(){
        for(ll i = 0; i < n; i++) root(i);
        for(ll i = 0; i < n; i++) group[parent[i]].push_back(i);
    }
    void clear(){
        for(ll i = 0; i < n; i++) { parent[i] = i; }
        siz = vector<ll>(n, 1);
        group.clear();
    }
    ll size(ll x){ return siz[root(x)]; }
};

mint fac(ll x) {
    mint res = 1;
    for(ll i = x; i > 1; i--) {
        res *= i;
    }
    return res;
}

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

    UnionFind cntr(n), cntc(n);
    rep(i, n)loop(j, i+1, n){
        bool flag = true;
        rep(l, n) {
            if(a[i][l] + a[j][l] > k) flag = false;
        }
        if(flag) cntr.unite(i, j);
    }
    rep(i, n)loop(j, i+1, n) {
        bool flag = true;
        rep(l, n) {
            if(a[l][i] + a[l][j] > k) flag = false;
        }
        if(flag) cntc.unite(i, j);
    }
    cntr.grouping();
    cntc.grouping();
    mint ansr = 1, ansc = 1, ans = 1;
    for(auto p : cntr.group) {
        ansr *= fac(p.second.size());
    }
    for(auto p : cntc.group) {
        ansc *= fac(p.second.size());;
    }
    ans *= ansr;
    ans *= ansc;
    cout << ans << endl;

    return 0;
}
