#pragma GCC optimize("O3")
#include<bits/stdc++.h> 
using namespace std;
using ll=long long;
using P=pair<ll,ll>;
template<class T> using V=vector<T>; 
#define fi first
#define se second
#define all(v) (v).begin(),(v).end()
const ll inf=(1e18);
const ll mod=998244353;
//const ll mod=1000000007;
const vector<int> dy={-1,0,1,0},dx={0,-1,0,1};
ll GCD(ll a,ll b) {return b ? GCD(b,a%b):a;}
ll LCM(ll c,ll d){return c/GCD(c,d)*d;}
struct __INIT{__INIT(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(20);}} __init;
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>void debag(const vector<T> &a){cerr<<"debag :";for(auto v:a)cerr<<v<<" ";cerr<<"\n";}
template<class T>void print(const vector<T> &a){for(auto v:a)cout<<v<<" ";cout<<"\n";}
struct mint{
using ull=unsigned long long int;
ull v;
mint(ll vv=0){s(vv%mod+mod);}
mint& s(ull vv){
v=vv<mod?vv:vv-mod;
return *this;
}
//オーバーロード
mint operator-()const{return mint()-*this;}//mint型にキャスト
mint&operator+=(const mint&val){return s(v+val.v);}
mint&operator-=(const mint&val){return s(v+mod-val.v);}
mint&operator*=(const mint&val){
v=ull(v)*val.v%mod;
return *this;
}
mint&operator/=(const mint&val){return *this*=val.inv();}
mint operator+(const mint&val){return mint(*this)+=val;}
mint operator-(const mint&val){return mint(*this)-=val;}
mint operator*(const mint&val){return mint(*this)*=val;}
mint operator/(const mint&val){return mint(*this)/=val;}
mint pow(ll n)const{
mint res(1),x(*this);
while(n){
if(n&1)res*=x;
x*=x;
n>>=1ll;
}
return res;
}
mint inv()const{return pow(mod-2);}
//拡張ユークリッドの互除法
/* mint inv()const{
int x,y;
int g=extgcd(v,mod,x,y);
assert(g==1);
if(x<0)x+=mod;
return mint(x);
}*/
friend ostream& operator<<(ostream&os,const mint&val){
return os<<val.v;
}//出力
bool operator<(const mint&val)const{return v<val.v;}
bool operator==(const mint&val)const{return v==val.v;}
bool operator>(const mint&val)const{return v>val.v;}
};
const ll MAX = 2000010;//設定
mint fac[MAX], finv[MAX], inv[MAX];
// テーブルを作る前処理
void init(){
fac[0] = fac[1] = 1;
for(int i=1;i<MAX;i++)fac[i]=fac[i-1]*i;
finv[MAX-1]=fac[MAX-1].inv();
for(int i=MAX-2;i>=0;i--)finv[i]=finv[i+1]*(i+1);
for(int i=MAX-2;i>=1;i--)inv[i]=finv[i]+fac[i-1];
}
//階乗
mint factor(ll n,ll k){
if (n<k) return 0;
if (n<0 || k<0) return 0;
return fac[n]*finv[k];
}
// 二項係数計算
mint COM(int n, int k){
if (n < k) return 0;
if (n < 0 || k < 0) return 0;
return fac[n] * finv[k] * finv[n - k];
}
class UF{
public:
	vector<int> par,num;
	int find(int v){
		return (par[v]==v)? v: (par[v]=find(par[v]));
	}
	explicit UF(int N):par(N),num(N,1){
		iota(all(par),0);
	}
	void unite(int u,int v){
		u=find(u),v=find(v);
		if(u==v)return;
		if(num[u]<num[v])swap(u,v);
		num[u]+=num[v];
		par[v]=u;
	}
	bool same(int u,int v){
		return find(u)==find(v);
	}
	bool ispar(int v){
		return v=find(v);
	}
	int size(int v){
		return num[find(v)];
	}
};
int main(){
    init();
    int n,K;
    cin>>n>>K;
    V<V<int>> a(n,V<int>(n));
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)cin>>a[i][j];
    }
    UF l(n);
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            bool ok=true;
            for(int k=0;k<n;k++){
                  if(a[i][k]+a[j][k]>K)ok=false;
            }
            if(ok)l.unite(i,j);
        }
    }
    mint ans=mint(1);
    for(int i=0;i<n;i++){
         if(l.find(i)!=i)continue;
         ans*=fac[l.size(i)];
    }
    UF r(n);
        for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            bool ok=true;
            for(int k=0;k<n;k++){
                  if(a[k][i]+a[k][j]>K)ok=false;
            }
            if(ok)r.unite(i,j);
        }
    }
        for(int i=0;i<n;i++){
         if(r.find(i)!=i)continue;
         ans*=fac[r.size(i)];
    }
    cout<<ans<<"\n";
}
    #include <bits/stdc++.h>
    using namespace std;
    #include <math.h>
    #include <iomanip>
    #include <cstdint>
    #include <string>
    #include <sstream>
    template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
    template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
    #define rep(i,n) for (int i = 0; i < (n); ++i)
    typedef long long ll;
    using P = pair<ll,ll>;
    const int mod=998244353;
    const int INF=1001001001;
    
    struct edge{
      int to;
      ll w;
      edge(int to,ll w):to(to),w(w){}
    };
    using Graph=vector<vector<edge>>;
    
    int N,M;
    
    void dijkstra(int s,Graph G,vector<ll>& dist){
      dist.resize(N,INF);
      dist[s]=0;
      priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<pair<ll,int>>>q;
      q.push({dist[s],s});
      while(!q.empty()){
        int v=q.top().second;
        ll d=q.top().first;
        q.pop();
        if(d>dist[v]){continue;}
        for(auto e:G[v]){
          if(chmin(dist[e.to],dist[v]+e.w)){
            q.push({dist[e.to],e.to});
          }
        }
      }
    }

    int main() {
      cin>>N>>M;
      Graph G(N);
      rep(i,M){
        ll A,B;
        cin>>A>>B;
        A--;B--;
        G[A].push_back(edge(B,1));
        G[B].push_back(edge(A,1));
      }
      int K;
      cin>>K;
      vector<int>C(K);
      rep(i,K){cin>>C[i];C[i]--;}

      vector<vector<int>>dist(K);
      rep(i,K){
        vector<ll>d(N,INF);
        dijkstra(C[i],G,d);
        rep(j,K){dist[i].push_back(d[C[j]]);}
      }
      vector<vector<ll>>dp(1<<K,vector<ll>(K,INF));
      rep(i,K){dp[1<<i][i]=0;}
      rep(s,1<<K){
        rep(i,K){
          if((s>>i)&1){
            ll res=s^(1<<i);
            rep(j,K){
              if(res&(1<<j)){chmin(dp[s][i],dp[res][j]+dist[i][j]);}
            }
          }
        }
      }
      ll ans=*min_element(dp.back().begin(),dp.back().end());
      cout<<(ans<INF?ans+1:-1)<<endl;
      return 0;
    }