#include <bits/stdc++.h>
#define MOD_10_9_7 1000000007
#define MOD 998244353;
#define all(x) x.begin(), x.end()
#define endl '\n'
using namespace std;
template <typename T>
void update_max(T& a, T b) {
    if (b > a) a = b;
}
template <typename T>
void update_min(T& a, T b) {
    if (b < a) a = b;
}

class DisjointSet {
    int size;
    int components;
    vector<int> parents;

   public:
    DisjointSet(int size) {
        this->size = size;
        this->parents = vector<int>(size);
        for (int i = 0; i < size; i++) {
            parents[i] = i;
        }
        components = size;
    };
    int find(const int index) {
        vector<int> path;
        int current = index;
        while (current != parents[current]) {
            path.push_back(current);
            current = parents[current];
        }
        for (int parent : path) {
            parents[parent] = current;
        }
        return current;
    };
    bool merge(const int index1, const int index2) {
        int parent1 = find(index1), parent2 = find(index2);
        if (parent1 != parent2) {
            parents[parent1] = parent2;
            components -= 1;
            return true;
        };
        return false;
    };
};

vector<long long> factorials;

int main() {
#ifdef LOCAL_PROJECT
    freopen("input.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N, K;
    cin >> N >> K;
    factorials = vector<long long>(N + 1, 1);
    for (int i = 2; i < N + 1; i++) {
        factorials[i] = (i * factorials[i - 1]) % MOD;
    }
    vector<vector<int>> a(N, vector<int>(N, 0));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> a[i][j];
        }
    }
    DisjointSet column_ds(N);  //= new DisjointSet(N);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < i; j++) {
            bool lower_than_k = true;
            for (int r = 0; r < N; r++) {
                if (a[r][i] + a[r][j] > K) {
                    lower_than_k = false;
                    break;
                }
            }
            if (lower_than_k) column_ds.merge(i, j);
        }
    }
    unordered_map<int, int> column_counter;
    for (int i = 0; i < N; i++) {
        column_counter[column_ds.find(i)] += 1;
    }

    DisjointSet row_ds(N);  //= new DisjointSet(N);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < i; j++) {
            bool lower_than_k = true;
            for (int r = 0; r < N; r++) {
                if (a[i][r] + a[j][r] > K) {
                    lower_than_k = false;
                    break;
                }
            }
            if (lower_than_k) row_ds.merge(i, j);
        }
    }
    unordered_map<int, int> row_counter;
    for (int i = 0; i < N; i++) {
        row_counter[row_ds.find(i)] += 1;
    }

    long long answer = 1;
    for (auto it : column_counter) {
        answer = (answer * factorials[it.second]) % MOD;
    }
    for (auto it : row_counter) {
        answer = (answer * factorials[it.second]) % MOD;
    }
    cout << answer;
    return 0;
}
#include <bits/stdc++.h>

using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;

#define REP(i, n, m) for(ll i=n; i<(ll)m; ++i)
#define IREP(i, n, m) for(ll i=n-1; i>=m; --i)
#define rep(i, n) REP(i, 0, n)
#define irep(i, n) IREP(i, n, 0)
#define all(v) v.begin(), v.end()
#define vprint(v) for(auto e:v){cout<<e<<" ";};cout<<endl;
#define vvprint(vv) for(auto v:vv){vprint(v)};

class UnionFind{
    public:
        ll size;
        vll v;

        UnionFind(ll n){
            this->v = vll(n);
            rep(i, n) this->v[i] = i;
        }

        ll root(ll n){
            if(n!=v[n]) return v[n] = root(v[n]);
            return n;
        }

        void unite(ll l, ll r){
            ll lroot = root(l);
            ll rroot = root(r);
            if(lroot!=rroot) this->v[rroot] = lroot;
        }
};

ll fac(ll n, ll mod=998244353){
    static const ll N_MAX = 200001;
    static vll fac(N_MAX+1, -1);

    if(fac[0]<0){
        fac[0] = 1;
        rep(i, N_MAX){
            fac[i+1] = fac[i] * (i+1) % mod;
        }
    }

    return fac[n] % mod;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(20);

    ll N, K;
    cin >> N >> K;
    vvll a(N, vll(N, 0));
    rep(i, N) rep(j, N){
        cin >> a[i][j];
    }

    UnionFind ufx(N), ufy(N);
    rep(i, N) REP(j, i+1, N){
        bool okx = true, oky = true;
        rep(k, N){
            okx &= a[k][i]+a[k][j] <= K;
            oky &= a[i][k]+a[j][k] <= K;
        }
        if(okx) ufx.unite(i, j);
        if(oky) ufy.unite(i, j);
    }

    unordered_map<ll, unordered_set<ll>> mx, my;
    rep(i, N){
        ll rx = ufx.root(i);
        ll ry = ufy.root(i);
        mx[rx].insert(i);
        my[ry].insert(i);
    }

    ll cx = 1, cy = 1;
    for(auto p : mx){
        cx = cx*fac(p.second.size()) % 998244353;
    }
    for(auto p : my){
        cy = cy*fac(p.second.size()) % 998244353;
    }
    ll ans = cx*cy % 998244353;
    cout << ans << endl;
}
