#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
const ll MOD = 1e+7;
const ld PI = acos(-1);  
const ld EPS = 1e-8;
const ll LINF = 1LL<<60;
const int INF = 1LL<<17;
#define rep(i, a, b) for(ll i=a; i<(ll)(b); i++)
#define rrep(i, a, b) for(ll i=b-1; a<=i; i--)
#define ALL(x) x.begin(), x.end()
#define MAX(x) *max_element(ALL(x))
#define MIN(x) *min_element(ALL(x))
ll ceil(ll a, ll b) {if(a==0) return 0; return (a-1)/b+1;}
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
string YES[2] = {"NO", "YES"};
string yes[2] = {"No", "Yes"};

template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD; 
    }
    constexpr int getmod() { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD; 
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};
using mint = Fp<998244353>;
struct UnionFind{

    vector<ll> par;
    UnionFind(ll n) : par(n, -1){}
    

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

    bool same(int a, int b){
        return root(a)==root(b);
    }
    void unite(int a, int b){
        int x=root(a), y=root(b);
        if(same(x, y)) return;
        if(y<x) swap(x, y);
        par[x] += par[y];
        par[y] = x;
    }
    int size(int x){
        return -par[root(x)];
    }

};

int main(){
    ll n, k;    cin >> n >> k;
    vector<vector<ll>> g(n, vector<ll>(n));
    rep(i, 0, n) rep(j, 0, n) cin >> g[i][j];
    mint res=1;
    rep(t, 0, 2){
        UnionFind tree(n);
        rep(i, 0, n){
            rep(j, i+1, n){
                bool flag=true;
                rep(p, 0, n){
                    if(t){
                        if(g[i][p]+g[j][p]>k) flag = false;
                    }else{
                        if(g[p][i]+g[p][j]>k) flag = false;
                    }
                }
                if(flag) tree.unite(i, j);
            }
        }
        set<ll> st;
        rep(i, 0, n) st.insert(tree.root(i));
        
        for(auto x: st){
            mint sum = 1;
            rep(i, 1, tree.size(x)+1) sum *= i;
            res *= sum;
        }
    }
    
    
    cout << res << endl;
}

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct edge{
	int to,next;
}e[10000];
int n,m,a[30],head[30],cnt,ans=1,res,t,b[30];
bool vis[30];
inline void add(int u,int v){
	cnt++;
	e[cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
inline void dfs1(int u){
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(vis[v])continue;
		vis[v]=1;
		b[++t]=v;
		dfs1(v);
	}
}
inline void dfs(int u,int s){
	bool tag[4],flag=0;
	memset(tag,0,sizeof(tag));
	int sum=0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(a[v]&&!tag[a[v]])tag[a[v]]=1,sum++;
	}
	if(sum==3)return;
	if(s==t){
		a[u]=0;
		for(int i=1;i<=3;i++)if(!tag[i])res++;
		return;
	}
	for(int j=1;j<=3;j++)
	if(!tag[j]){
		flag=0;
		a[u]=j;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(a[v])continue;
			flag=1;
			dfs(v,s+1);
			break;
		}
		if(!flag){
		    for(int i=1;i<=t;i++)
		    if(!a[b[i]]){
			    dfs(b[i],s+1);
			    break;
		    }
	    }
	}
	a[u]=0;
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1,x,y;i<=m;i++){
		scanf("%lld%lld",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
	if(!vis[i]){
		vis[i]=1;
		t=1;
		b[1]=i;
		dfs1(i);
		//cout<<t<<endl;
		res=0;
		dfs(i,1);
		ans*=res;
	}
	printf("%lld",ans);
	return 0;
}