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

#define INF 1e9
#define rep(i,n)for(int i=0;(i)<(int)(n);i++)
#define REP(i,a,b)for(int i=(int)(a);(i)<=(int)(b);i++)
#define ALL(a)  (a).begin(),(a).end()
#define chmax(a, b) a = max(a, b)
#define chmin(a, b) a = min(a, b)
#define pb push_back
#define fi first
#define se second
#define sz(x) ((int)x.size())

using namespace std;
//using namespace atcoder;
using ld = long double;
using ll = long long;
//using P = pair<ll, ll>;
using Graph = vector<vector<int>>;
//using mint = modint998244353;

const ll ZER = 0;
const ll MOD =  998244353 ;

// UnionFind木(サイズ持ち)
class UnionFind {
    public : 

        vector<int> par;

        UnionFind(int N){
            par = vector<int>(N, -1);
        }

        int parent(int x){
            return par[x];
        }

        int root(int x){
            if(par[x] < 0)return x;
            return par[x] = root(par[x]);
        }

        int size(int x){
            return -par[root(x)];
        }

        void merge(int x, int y){
            int rx = root(x);
            int ry = root(y);
            if(rx == ry)return;

            if(size(rx) < size(ry))swap(rx, ry);

            par[rx] += par[ry];
            par[ry] = rx;

            return;
        }

        bool same(int x, int y){
            return root(x) == root(y);
        }
};

int main(){
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, K;
    cin >> n >> K;
    vector<ll> fac(1001, 1);
    REP(i, 2, 1000){
        fac[i] = fac[i - 1] * i;
        fac[i] %= MOD;
    }
    vector<vector<int>> a(n, vector<int>(n));
    rep(i, n)rep(j, n)cin >> a[i][j];
    UnionFind uf1(n), uf2(n);;
    rep(i, n){
        REP(j, i + 1, n - 1){
            bool f = true;
            rep(k, n){
                if(a[i][k] + a[j][k] > K)f = false;
            }
            if(f)uf1.merge(i, j);
        }
    }
    rep(i, n){
        REP(j, i + 1, n - 1){
            bool f = true;
            rep(k, n){
                if(a[k][i] + a[k][j] > K)f = false;
            }
            if(f)uf2.merge(i, j);
        }
    }
    ll tate = 1;
    vector<bool> se1(n, false);
    rep(i, n){
        if(se1[uf1.root(i)])continue;
        tate *= fac[uf1.size(i)];
        tate %= MOD;
        se1[uf1.root(i)] = true;
    }
    ll yoko = 1;
    vector<bool> se2(n, false);
    rep(i, n){
        if(se2[uf2.root(i)])continue;
        yoko *= fac[uf2.size(i)];
        yoko %= MOD;
        se2[uf2.root(i)] = true;
    }
    ll res = tate * yoko % MOD;
    cout << res << endl;
}
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 998244353;
const int N = 55;
int n, k, a[N][N], fac[N], far[N], s1[N], s2[N], flag[N];
ll ans = 1;
int find1(int x) {
	return far[x] == x ? x : far[x] = find1(far[x]);
}
int find2(int x) {
	return fac[x] == x ? x : fac[x] = find2(fac[x]);
}
int main() {
	cin>>n>>k;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++) cin>>a[i][j];
	for (int i = 1; i <= n; i++) far[i] = fac[i] = i, s1[i] = s2[i] = 1;
	for (int r1 = 1; r1 <= n; r1++)
		for (int r2 = r1 + 1; r2 <= n; r2++) {
			bool flag = true;
			for (int j = 1; j <= n; j++)
				if (a[r1][j] + a[r2][j] > k) flag = false;
			if (flag)
				if (find1(r1) != find1(r2)) s1[find1(r2)] += s1[find1(r1)], far[find1(r1)] = find1(r2);
		}
	for (int c1 = 1; c1 <= n; c1++)
		for (int c2 = c1 + 1; c2 <= n; c2++) {
			bool flag = true;
			for (int i = 1; i <= n; i++)
				if (a[i][c1] + a[i][c2] > k) flag = false;
			if (flag)
				if (find2(c1) != find2(c2)) s2[find2(c2)] += s2[find2(c1)], fac[find2(c1)] = find2(c2);
		}
	for (int i = 1; i <= n; i++)
		if (!flag[find1(i)]) {
			flag[find1(i)] = 1;
			for (int j = 2; j <= s1[find1(i)]; j++)
				ans = ans * j % mod;
		}
	for (int i = 1; i <= n; i++) flag[i] = 0;
	for (int i = 1; i <= n; i++)
		if (!flag[find2(i)]) {
			flag[find2(i)] = 1;
			for (int j = 1; j <= s2[find2(i)]; j++)
				ans = ans * j % mod;
		}
	cout<<ans;
	return 0;
}