#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define y1 Y1
const int INF=1<<29;
const int MAXN=500;
struct edge
{
    int a,b,cap,flow;
};
bool m[11][11];
vector <int> g[MAXN];
vector <edge> e;
int d[MAXN],ptr[MAXN],n,xb,yb,t,temp[11][11],kaps[11][11];
int way(int x1,int y1,int x2,int y2)
{
    queue <pair <int,pair <int,int> > > l;
    l.push(make_pair(0,make_pair(x1,y1)));
    int h[11][11];
    for(int p=0;p<n;p++)
        for(int b=0;b<n;b++)
            h[p][b]=INF;
    while (!l.empty())
    {
        int v=l.front().first,x=l.front().second.first,y=l.front().second.second;
        l.pop();
        h[x][y]=v;
        if (x>0 && m[x-1][y] && h[x-1][y]>h[x][y]+1 && (x-1==x2 && y==y2 && temp[x-1][y]>=h[x][y]+1 || !(x-1==x2 && y==y2) && temp[x-1][y]>h[x][y]+1)) l.push(make_pair(v+1,make_pair(x-1,y)));
        if (y>0 && m[x][y-1] && h[x][y-1]>h[x][y]+1 && (x==x2 && y-1==y2 && temp[x][y-1]>=h[x][y]+1 || !(x==x2 && y-1==y2) && temp[x][y-1]>h[x][y]+1)) l.push(make_pair(v+1,make_pair(x,y-1)));
        if (x<n-1 && m[x+1][y] && h[x+1][y]>h[x][y]+1 && (x+1==x2 && y==y2 && temp[x+1][y]>=h[x][y]+1 || !(x+1==x2 && y==y2) && temp[x+1][y]>h[x][y]+1)) l.push(make_pair(v+1,make_pair(x+1,y)));
        if (y<n-1 && m[x][y+1] && h[x][y+1]>h[x][y]+1 && (x==x2 && y+1==y2 && temp[x][y+1]>=h[x][y]+1 || !(x==x2 && y+1==y2) && temp[x][y+1]>h[x][y]+1)) l.push(make_pair(v+1,make_pair(x,y+1)));
    }
    return h[x2][y2];
}
void add_edge(int a,int b,int cap)
{
    edge e1={a,b,cap,0};
    edge e2={b,a,0,0};
    g[a].push_back((int)e.size());
    e.push_back(e1);
    g[b].push_back((int)e.size());
    e.push_back(e2);
}
bool bfs()
{
    queue <int> q;
    q.push(0);
    memset(d,-1,(n*n*2+2)*sizeof d[0]);
    d[0]=0;
    while (!q.empty() && d[n*n*2+1]==-1)
    {
        int v=q.front();
        q.pop();
        for(size_t j=0;j<g[v].size();j++)
        {
            int id=g[v][j],to=e[id].b;
            if (d[to]==-1 && e[id].flow<e[id].cap)
            {
                q.push(to);
                d[to]=d[v]+1;
            }
        }
    }
    return d[n*n*2+1]!=-1;
}
int dfs(int v,int flow)
{
    if (!flow) return 0;
    if (v==n*n*2+1) return flow;
    for(;ptr[v]<(int)g[v].size();ptr[v]++)
    {
        int id=g[v][ptr[v]],to=e[id].b;
        if (d[to]!=d[v]+1) continue;
        int pushed=dfs(to,min(flow,e[id].cap-e[id].flow));
        if (pushed)
        {
            e[id].flow+=pushed;
            e[id^1].flow-=pushed;
            return pushed;
        }
    }
    return 0;
}
int max_flow()
{
    int flow=0;
    for(;;)
    {
        if (!bfs()) break;
        memset(ptr,0,(n*n*2+2)*sizeof ptr[0]);
        while (int pushed=dfs(0,INF))
            flow+=pushed;
    }
    return flow;
}
int main()
{
    cin>>n>>t;
    queue <pair <int,pair <int,int> > > l;
    char x;
    int k=1;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cin>>x;
            temp[i][j]=t;
            if (x=='Z')
            {
                xb=i;
                yb=j;
                m[i][j]=false;
            } else
            if (x=='Y') m[i][j]=false; else m[i][j]=true;
            add_edge(0,k++,x=='Z' || x=='Y'?0:x-48);
        }
    }
    k=n*n+1;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            cin>>x;
            if (x>='0' && x<='9') kaps[i][j]=x-48;
            add_edge(k++,n*n*2+1,x=='Z' || x=='Y'?0:x-48);
        }
    l.push(make_pair(0,make_pair(xb,yb)));
    while (!l.empty())
    {
        int v=l.front().first,x=l.front().second.first,y=l.front().second.second;
        l.pop();
        temp[x][y]=v;
        if (x>0 && v+1<temp[x-1][y] && m[x-1][y]) l.push(make_pair(v+1,make_pair(x-1,y)));
        if (y>0 && v+1<temp[x][y-1] && m[x][y-1]) l.push(make_pair(v+1,make_pair(x,y-1)));
        if (x<n-1 && v+1<temp[x+1][y] && m[x+1][y]) l.push(make_pair(v+1,make_pair(x+1,y)));
        if (y<n-1 && v+1<temp[x][y+1] && m[x][y+1]) l.push(make_pair(v+1,make_pair(x,y+1)));
    }
    /*for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            cout<<temp[i][j]<<" ";
        cout<<endl;
    }*/
    k=0;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            int k1=n*n;
            k++;
            for(int z=0;z<n;z++)
                for(int w=0;w<n;w++)
                {
                    k1++;
                    if (m[i][j] && m[z][w] && way(i,j,z,w)<=t) add_edge(k,k1,INF);
                }
        }
    /*for(int i=0;i<n*n*2+1;i++)
        for(size_t j=0;j<g[i].size();j++)
            if (e[g[i][j]].cap>0) cout<<i<<" "<<e[g[i][j]].b<<" "<<e[g[i][j]].cap<<endl;*/
    cout<<max_flow();
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
char s1[15][15], s2[15][15];
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int idx[65][15][15];
int dp[15][15];
int id = 1;

typedef long long LL;
struct Edge {
  int u, v;
  LL cap, flow;
  Edge() {}
  Edge(int u, int v, LL cap): u(u), v(v), cap(cap), flow(0) {}
};

struct Dinic {
  int N;
  vector<Edge> E;
  vector<vector<int>> g;
  vector<int> d, pt;

  Dinic(int N): N(N), E(0), g(N), d(N), pt(N) {}

  void AddEdge(int u, int v, LL cap) {
    if (u != v) {
      E.emplace_back(Edge(u, v, cap));
      g[u].emplace_back(E.size() - 1);
      E.emplace_back(Edge(v, u, 0));
      g[v].emplace_back(E.size() - 1);
    }
  }

  bool BFS(int S, int T) {
    queue<int> q({S});
    fill(d.begin(), d.end(), N + 1);
    d[S] = 0;
    while(!q.empty()) {
      int u = q.front(); q.pop();
      if (u == T) break;
      for (int k: g[u]) {
        Edge &e = E[k];
        if (e.flow < e.cap && d[e.v] > d[e.u] + 1) {
          d[e.v] = d[e.u] + 1;
          q.emplace(e.v);
        }
      }
    }
    return d[T] != N + 1;
  }

  LL DFS(int u, int T, LL flow = -1) {
    if (u == T || flow == 0) return flow;
    for (int &i = pt[u]; i < g[u].size(); ++i) {
      Edge &e = E[g[u][i]];
      Edge &oe = E[g[u][i]^1];
      if (d[e.v] == d[e.u] + 1) {
        LL amt = e.cap - e.flow;
        if (flow != -1 && amt > flow) amt = flow;
        if (LL pushed = DFS(e.v, T, amt)) {
          e.flow += pushed;
          oe.flow -= pushed;
          return pushed;
        }
      }
    }
    return 0;
  }

  LL MaxFlow(int S, int T) {
    LL total = 0;
    while (BFS(S, T)) {
      fill(pt.begin(), pt.end(), 0);
      while (LL flow = DFS(S, T))
        total += flow;
    }
    return total;
  }
};

int main(){
	memset(dp, -1, sizeof(dp));
	int n, t;
	scanf("%d%d", &n, &t);
	for(int i=1;i<=n;i++){
		scanf("%s", s1[i]+1);
	}
	for(int i=0;i<=t+1;i++){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;k++){
				idx[i][j][k] = id++;
			}
		}
	}
	id++;
	for(int i=1;i<=n;i++){
		scanf("%s", s2[i]+1);
	}
	queue<pii> q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s1[i][j] == 'Z'){
				q.push(pii(i, j));
				dp[i][j] = 0;
			}
		}
	}
	while(!q.empty()){
		int uy = q.front().first, ux = q.front().second;
		q.pop();
		for(int i=0;i<4;i++){
			int vy = uy+dir[i][0], vx = ux+dir[i][1];
			if(vy >= 1 && vy <= n && vx >= 1 && vx <= n && s1[vy][vx] != 'Y' && dp[vy][vx] == -1){
				dp[vy][vx] = dp[uy][ux] + 1;
				q.push(pii(vy, vx));
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dp[i][j] == -1) dp[i][j] = 1e9;
			if(dp[i][j] > t) dp[i][j] = 1e9;
		}
	}
	int source = 0, sink = id-1;
	Dinic dinic(id);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s1[i][j] >= '1' && s1[i][j] <= '9'){
				dinic.AddEdge(source, idx[0][i][j], s1[i][j]-'0');
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s1[i][j] == 'Y' || s1[i][j] == 'Z') continue;
			for(int k=0;k<4;k++){
				int vy = i+dir[k][0], vx = j+dir[k][1];
				if(vy >= 1 && vy <= n && vx >= 1 && vx <= n && s1[vy][vx] != 'Y' && s1[vy][vx] != 'Z'){
					for(int x=0;x<t;x++){
						if(dp[vy][vx] >= x+1 && dp[i][j] > x){
							dinic.AddEdge(idx[x][i][j], idx[x+1][vy][vx], 1000);
						}
					}
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s1[i][j] == 'Y' || s1[i][j] == 'Z') continue;
			for(int x=0;x<=t;x++){
				if(s2[i][j] >= '1' && s2[i][j] <= '9'){
					dinic.AddEdge(idx[x][i][j], idx[t+1][i][j], s2[i][j]-'0');
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s1[i][j] == 'Y' || s1[i][j] == 'Z') continue;
			if(s2[i][j] >= '1' && s2[i][j] <= '9'){
				dinic.AddEdge(idx[t+1][i][j], sink, s2[i][j]-'0');
			}
		}
	}
	printf("%d\n", dinic.MaxFlow(source, sink));
}


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int, int> pii;
typedef pair <int, string> pis;
#define f first
#define s second
#define mp make_pair
#define pb push_back
const int N = 11;
const int INF = 1e9;
const int SIZE = 2 * N * N;

struct edge
{
  int to, c, f, rev;
  edge() {}
  edge(int too, int cc, int ff, int revv)
  {
    to = too;
    c = cc;
    f = ff;
    rev = revv;
  }
};

vector <edge> g[SIZE];
int d[SIZE], ptr[SIZE], s, t, n;
queue <int> q;

void addEdge(int v, int u, int cap)
{
  g[v].pb(edge(u, cap, 0, 0));
  g[u].pb(edge(v, 0, 0, 0));
  g[v].back().rev = g[u].size() - 1;
  g[u].back().rev = g[v].size() - 1;
}
bool buildLevNet()
{
  for (int i = 0; i <= t; ++i)
    d[i] = INF;
  d[s] = 0;
  q.push(s);
  while (!q.empty())
  {
    int v = q.front();
    q.pop();
    for (int i = 0; i < g[v].size(); ++i)
    {
      int to = g[v][i].to;
      int cf = g[v][i].c - g[v][i].f;
      if (d[to] == INF && cf > 0)
      {
        d[to] = d[v] + 1;
        q.push(to);
      }
    }
  }
  return d[t] != INF;
}

int dfs(int v, int curFlow)
{
  if (v == t) return curFlow;
  for (int& i = ptr[v]; i < g[v].size(); ++i)
  {
    int to = g[v][i].to;
    int cf = g[v][i].c - g[v][i].f, addFlow;
    if (d[to] == d[v] + 1 && cf > 0 && (addFlow = dfs(to, min(curFlow, cf))))
    {
      g[v][i].f += addFlow;
      g[to][g[v][i].rev].f -= addFlow;
      return addFlow;
    }
  }
  return 0;
}

int dinica()
{
  int flow = 0;
  while (buildLevNet())
  {
    memset(ptr, 0, sizeof(ptr));
    int add;
    while ((add = dfs(s, INF)))
      flow += add;
  }
  return flow;
}

queue <pii> go;
const int X[] = {-1, 1, 0, 0};
const int Y[] = {0, 0, -1, 1};
int dst[N][N][N][N], tbad;
char a[N][N], b[N][N];
pii bad;
bool check(pii v)
{
  return v.f >= 0 && v.f < n && v.s >= 0 && v.s < n && a[v.f][v.s] != 'Y' && a[v.f][v.s] != 'Z';
}
void bfs(int xs, int ys)
{
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      dst[xs][ys][i][j] = INF;
  dst[xs][ys][xs][ys] = 0;
  go.push(mp(xs, ys));
  while (!go.empty())
  {
    pii v = go.front();
    go.pop();
    if (dst[xs][ys][v.f][v.s] == dst[bad.f][bad.s][v.f][v.s] && (bad.f != xs || bad.s != ys)) continue;
    for (int i = 0; i < 4; ++i)
    {
      pii nv = mp(v.f + X[i], v.s + Y[i]);
      if (check(nv) && dst[xs][ys][nv.f][nv.s] == INF && dst[xs][ys][v.f][v.s] + 1 <= dst[bad.f][bad.s][nv.f][nv.s])
      {
        dst[xs][ys][nv.f][nv.s] = dst[xs][ys][v.f][v.s] + 1;
        go.push(nv);
      }
    }
  }
}

int main()
{
  cin >> n >> tbad;
  int px, py;
  for (int i = 0; i < n; ++i)
    for (int j  = 0; j < n; ++j)
    {
      cin >> a[i][j];
      if (a[i][j] == 'Z') px = i, py = j;
    }
  for (int i = 0; i < n; ++i)
    for (int j  = 0; j < n; ++j)
      cin >> b[i][j];
  bad = mp(px, py);
  bfs(px, py);
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      dst[bad.f][bad.s][i][j] = min(dst[bad.f][bad.s][i][j], tbad);
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      if (check(mp(i, j))) bfs(i, j);
  s = 0;
  t = 2 * n * n + 1;
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
    {
      if (a[i][j] != '0') addEdge(s, i * n + j + 1, a[i][j] - '0');
      if (b[i][j] != '0') addEdge(i * n + j + 1 + n * n, t, b[i][j] - '0');
    }
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      for (int i1 = 0; i1 < n; ++i1)
        for (int j1 = 0; j1 < n; ++j1)
          if (check(mp(i, j)) && check(mp(i1, j1)) && dst[i][j][i1][j1] <= dst[px][py][i1][j1])
            addEdge(i * n + j + 1, i1 * n + j1 + 1 + n * n, INF);
  cout << dinica();

/*
2 60
00
Z1

00
Z1
*/
  return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct networkflow{
    struct node{
        int v, w, rev;
    };
    void setEdge(int u, int v, int fl){
        int sz1= (int)adj[v].size();
        int sz2 = (int)adj[u].size();
        adj[u].push_back({v, fl, sz1});
        adj[v].push_back({u, 0, sz2});
    }
    vector<vector<node> > adj;
    vector<int> lev, edge_tried;
    int st, ed;
    networkflow(int V, int s, int t): adj(V), lev(V), edge_tried(V), st(s), ed(t){}
    bool assign_level(){
        fill(lev.begin(), lev.end(), -1);
        lev[st]=0;
        queue<int>que;que.push(st);
        while(!que.empty()){
            int now =que.front();que.pop();
            for(int i=0; i<adj[now].size(); i++){
                int nxt = adj[now][i].v;
                if(lev[nxt]==-1 && adj[now][i].w!=0){
                    lev[nxt] =  lev[now]+1;
                    que.push(nxt);
                }
            }
        }
        return (lev[ed]!=-1);
    }
    int dfs(int now, int fl){
        if(now==ed)return fl;
        for(int &i=edge_tried[now]; i<adj[now].size(); i++){
            int nxt = adj[now][i].v;
            if(lev[nxt]==lev[now]+1 && adj[now][i].w!=0){
                int nxtflow = dfs(nxt, min(fl, adj[now][i].w));
                if(nxtflow){
                    adj[now][i].w-=nxtflow;
                    adj[nxt][adj[now][i].rev].w+=nxtflow;
                    return nxtflow;
                }
            }
        }
        return 0;
    }
    ll dinic(){
        ll ret=0;
        while(assign_level()){
            fill(edge_tried.begin(), edge_tried.end(), 0);
            while(1){
                int amt = dfs(st, 2e9);
                if(amt==0)break;
                ret+=amt;
            }
        }
        return ret;
    }
};

int n, ti, ck[15][15];
string str[15], es[15];
int yy, xx;
int dy[]={1, -1, 0, 0};
int dx[]={0, 0, 1, -1};
void go()
{
    queue<pair<int, int> >que;que.push({yy, xx});
    ck[yy][xx]=1;
    int lev=1;
    while(!que.empty()){
        int sz = (int)que.size();
        for(int ite=0; ite<sz; ite++){
        pair<int, int> now = que.front();que.pop();
        for(int i=0; i<4; i++){
            int ny = now.first + dy[i];
            int nx = now.second + dx[i];
            if(!(ny>=0 && ny<n &&nx>=0 && nx<n))continue;
            if(ck[ny][nx] || str[ny][nx]=='Y')continue;
            ck[ny][nx] = lev;
            que.push({ny, nx});
        }
        }
        ++lev;
        lev=min(lev, ti);
    }
}
int table[15][15][65];
int main()
{
    cin>>n>>ti;
    for(int i=0; i<n; i++){
        cin>>str[i];
        for(int j=0 ;j<n; j++){
            if(str[i][j] =='Z'){
                    yy=i, xx=j;
            }
        }
    }
    getline(cin, str[n]);
    getline(cin, str[n]);

    for(int i=0; i<n; i++){
        cin>>es[i];
    }
    go();
    int nodecnt=0;

    for(int i=0; i<n; i++){
        for(int j=0 ;j<n; j++){
            if('0'<=str[i][j] &&str[i][j]<='9'){
                if(ck[i][j]==0)ck[i][j] = ti;
                for(int t =0; t<ck[i][j]; t++){
                    table[i][j][t]=++nodecnt;
                }
            }
            if('1'<=es[i][j] && es[i][j] <='9'){
                table[i][j][ck[i][j]]=++nodecnt;
            }
        }
    }

    int INF = (int)1e9;
    int st= 0, ed = nodecnt+3;
    networkflow net(nodecnt+5, st, ed);
    for(int i=0; i<n; i++){
        for(int j=0 ;j<n; j++){
             if('1'<=str[i][j] &&str[i][j]<='9'){
                    net.setEdge(st, table[i][j][0], str[i][j]-'0');
             }

             for(int ite=0; ite<4; ite++){
                int ny = i + dy[ite];
                int nx = j + dx[ite];
                if(!(ny>=0 && ny<n &&nx>=0 &&nx<n))continue;
                if(str[ny][nx]=='Y' || str[ny][nx]=='Z')continue;
                for(int t=0; ; t++){
                    if(table[i][j][t]==0)break;
                    if(t==ck[i][j] && es[i][j]>='1' && es[i][j]<='9')break;///마지막골인 가능하지만 뿌려선 안됨
                    if(table[ny][nx][t+1]){
                        net.setEdge(table[i][j][t], table[ny][nx][t+1], INF);
                    }
                }
             }

            if('1'<=es[i][j] &&es[i][j]<='9'){
                for(int t = 0; t<ck[i][j]; t++){
                    net.setEdge(table[i][j][t], table[i][j][t+1], INF);
                }
                net.setEdge(table[i][j][ck[i][j]], ed, es[i][j]-'0');
            }
        }
    }
    int ans = net.dinic();
    cout<<ans<<endl;

}


//http://codeforces.com/problemset/problem/78/E
//Evacuation

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 300;

const int ROOM = -1;
const int REAC = -2;
const int BAD_REAC = -3;
const int CAPS = ROOM;

class Aresta {
public:
    int from, to, rev, flow, cap;
    Aresta(){}
    Aresta(int _from, int _to, int _rev, int _flow, int _cap){
        from = _from; to = _to; rev = _rev; flow = _flow; cap = _cap;
    }
    int residuo() {return cap-flow;}
};

class EdmondsKarp {
public:
    int size;
    vector<Aresta*> *grafo;
    Aresta **prev;
    bool *vis;

    EdmondsKarp(int tam){
        size = tam;
        grafo = new vector<Aresta*>[size];
        prev = new Aresta*[size];
        vis = new bool[size];
    }

    void limpa(){
        for (int i=0; i<size; i++){
            for (size_t j=0; j<grafo[i].size(); j++){
                delete grafo[i][j];
            }
            grafo[i].clear();
        }
    }

    void destroy(){
        limpa();
        delete prev;
        delete vis;
        delete this;
    }

    void add(int s, int t, int cap){
        Aresta *a = new Aresta(s, t, grafo[t].size(), 0, cap);
        Aresta *b = new Aresta(t, s, grafo[s].size(), 0, 0);
        grafo[s].push_back(a);
        grafo[t].push_back(b);
    }

    void undirectedAdd(int s, int t, int cap){
        Aresta *a = new Aresta(s, t, grafo[t].size(), 0, cap);
        Aresta *b = new Aresta(t, s, grafo[s].size(), 0, cap);
        grafo[s].push_back(a);
        grafo[t].push_back(b);
    }

    bool bfs(int source, int sink){
        for (int i=0; i<size; i++){
            prev[i] = NULL;
            vis[i] = false;
        }

        queue<int> fila;
        fila.push(source);
        vis[source] = 1;

        int atual;
        while (!fila.empty()){
            atual = fila.front(); fila.pop();

            if (atual == sink) return true;

            for (Aresta *a : grafo[atual]){
                if (!vis[a->to] && a->residuo() > 0){
                    prev[a->to] = a;
                    vis[a->to] = true;
                    fila.push(a->to);
                }
            }
        }

        return false;
    }

    int dfs(int source, int sink){
        int flow = INT_MAX;
        int v = sink;
        while (v != source){
            flow = min(flow, prev[v]->residuo());
            v = prev[v]->from;
        }

        v = sink;
        Aresta *a;
        while (v != source){
            a = prev[v];
            a->flow += flow;
            grafo[a->to][a->rev]->flow -= flow;
            v = a->from;
        }
        return flow;
    }

    long long int flow(int source, int sink){
        int flow = 0;
        while (bfs(source, sink)){
            flow += dfs(source, sink);
        }
        return flow;
    }
};

int station[MAXN][MAXN], checkpoint[MAXN][MAXN], veneno[61][MAXN][MAXN];

struct coord{
    int x, y, qtd;
    coord(int a, int b, int c){
        x = a; y = b; qtd = c;
    }
    bool is_valid(int N){
        return (x >= 0 && x < N && y >= 0 && y < N && station[x][y] == ROOM);
    }
};

bool is_valid(int x, int y, int N){
    return coord(x, y, 0).is_valid(N);
}

inline bool operator == (const coord &a, const coord &b){
    return (a.x == b.x && a.y == b.y);
}

vector<coord> pessoas, capsulas;
int moveX[] = {-1, 0, 1, 0};  //^<v>
int moveY[] = {0, -1, 0, 1};  //^<v>

int trad(char ch){
    switch (ch) {
        case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
            return ROOM;
        case 'Y':
            return REAC;
        case 'Z':
            return BAD_REAC;
    }
    return -1;
}

int how_much(char ch){
    return ch-'0';
}

int bfs(coord from, coord to, int N){
    bitset<MAXN> vis[MAXN];
    queue<pair<int, coord>> fila;
    fila.push({0, from});
    vis[from.x][from.y] = 1;

    while (!fila.empty()){
        int tempo = fila.front().first;
        coord atual = fila.front().second;
        fila.pop();

        if (atual == to) return tempo;

        if (veneno[tempo][atual.x][atual.y]){
            continue;
        }

        for (int i=0; i<4; i++){
            coord next(atual.x + moveX[i], atual.y + moveY[i], 0);
            if (next.is_valid(N) && !vis[next.x][next.y]){
                if (!veneno[tempo][next.x][next.y]){
                    fila.push({tempo + 1, next});
                    vis[next.x][next.y] = 1;
                }
            }
        }
    }

    return 999;
}

void espalha_veneno(int x, int y, int T, int N){
    veneno[0][x][y] = 1;
    for (int i=1; i<=T; i++){
        for (int lin=0; lin<N; lin++){
            for (int col=0; col<N; col++){
                if (veneno[i-1][lin][col]){
                    veneno[i][lin][col] = 1;
                    for (int move=0; move<4; move++){
                        if (is_valid(lin+moveX[move], col+moveY[move], N)){
                            veneno[i][lin+moveX[move]][col+moveY[move]] = 1;
                        }
                    }
                }
            }
        }
    }

}

int main(){
    int N, T;
    scanf(" %d %d", &N, &T);

    char ch;
    coord bad = {0, 0, 0};
    for (int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            scanf(" %c", &ch);
            if (trad(ch) == ROOM && how_much(ch)){
                pessoas.push_back(coord(i, j, how_much(ch)));
            }
            station[i][j] = trad(ch);
            if (station[i][j] == BAD_REAC){
                bad = coord(i, j, 0);
            }
        }
    }

    for (int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            scanf(" %c", &ch);
            if (trad(ch) == CAPS && how_much(ch)){
                capsulas.push_back(coord(i, j, how_much(ch)));
                checkpoint[i][j] = how_much(ch);
            }
        }
    }

    EdmondsKarp *din = new EdmondsKarp(MAXN);
    int sink = MAXN-1;

    for (size_t i=0; i<pessoas.size(); i++){
        din->add(0, i*2+1, pessoas[i].qtd);
    }

    for (size_t i=0; i<capsulas.size(); i++){
        din->add(i*2+2, sink, capsulas[i].qtd);
    }

    espalha_veneno(bad.x, bad.y, T, N);

    for (size_t i=0; i<pessoas.size(); i++){
        for (size_t j=0; j<capsulas.size(); j++){
            int tempo = bfs(pessoas[i], capsulas[j], N);
            if (tempo <= T){
                din->add(i*2+1, j*2+2, 999);
            }
        }
    }

    printf("%lld\n", din->flow(0, sink));
    delete din;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());

#define int long long
#define ll long long
#define mp make_pair
#define f first
#define s second
#define pii pair<int, int>
#define all(_v) _v.begin(), _v.end()
#define sz(a) ((int)a.size())
#define what_is(x) cout << #x << " is " << x << endl;
typedef long double ld;

const ll inf = 1e17 + 7;
const int max_n = 1001;

int xdir[]{0, 0, -1, 1}, ydir[]{-1, 1, 0, 0};

vector<int> gr[max_n];
bool used[max_n];
int pa[max_n];

bool check(int x, int y, vector<string>& s) {
    return x >= 0 && y >= 0 && x < s.size() && y < s.size() && s[x][y] != 'Y' && s[x][y] != 'Z';
}

vector<vector<int>> bfs(int st_x, int st_y, vector<string> s) {
    vector<vector<int>> res(s.size(), vector<int>(s.size(), inf));
    res[st_x][st_y] = 0;
    deque<pii> b;
    b.emplace_back(st_x, st_y);

    while(b.size()) {
        pii v = b.front();
        b.pop_front();

        for(int i = 0;i < 4;i++) {
            int x = v.f + xdir[i];
            int y = v.s + ydir[i];
            if (!check(x, y, s) || res[x][y] != inf) continue;

            res[x][y] = res[v.f][v.s] + 1;
            b.emplace_back(x, y);
        }
    }

    return res;
}

void scan() {
    int n, t;
    cin >> n >> t;
    vector<string> s1(n), s2(n);
    for(int i = 0;i < n;i++)
        cin >> s1[i];

    for(int i = 0;i < n;i++)
        cin >> s2[i];

    int x_reac, y_reac;
    for(int i = 0;i < n;i++) {
        for(int j = 0;j < n;j++) {
            if (s1[i][j] == 'Z') {
                x_reac = i;
                y_reac = j;
            }
        }
    }

    vector<vector<int>> reac = bfs(x_reac, y_reac, s1);

    for(int i = 0;i < n;i++) {
        for(int j = 0;j < n;j++) {
            if (!check(i, j, s1)) continue;
            vector<vector<int>> a = bfs(i, j, s1);

            for(int x = 0;x < n;x++) {
                for(int y = 0;y < n;y++) {
                    if (!check(x, y, s1) || a[x][y] > t || a[x][y] > reac[x][y]) continue;

                    if (a[x][y] == reac[x][y]) {
                        bool good = false;
                        for(int id = 0;id < 4;id++) {
                            int xto = x + xdir[id];
                            int yto = y + ydir[id];
                            if (!check(xto, yto, s1) ||  a[xto][yto] >= reac[xto][yto]) continue;
                            good = true;
                        }
                        if (!good) continue;
                    }

                    for(int num1 = 1;num1 <= s1[i][j] - '0';num1++) {
                        for(int num2 = 1;num2 <= s2[x][y] - '0';num2++) {
                            gr[10 * (j + i * 10) + num1].emplace_back(10 * (y + 10 * x) + num2);
                        }
                    }
                }
            }
        }
    }
}

bool kuhn(int v) {
    if (used[v]) return false;
    used[v] = true;
    for(int to : gr[v]) {
        if (pa[to] == 0 || kuhn(pa[to])) {
            pa[to] = v;
            return true;
        }
    }
    return false;
}

void solve() {
    scan();

    int n = max_n;

    for(int i = 0;i < n;i++) {
        kuhn(i);
        for(int j = 0;j < n;j++)
            used[j] = false;
    }

    int res = 0;
    for(int i = 0;i < n;i++) res += pa[i] != 0;

    cout << res;
}

signed main() {
    cin.tie(0);
    cout.tie(0);
    ios_base::sync_with_stdio(0);
    cout.precision(10);

    solve();
}


//In the name of God

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

template<class P, class Q> inline P smin(P &a, Q b) { if (b < a) a = b; return a; }
template<class P, class Q> inline P smax(P &a, Q b) { if (a < b) a = b; return a; }

#define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++)

const int N = 205, M = N * N;
#define prev some

int read() { int x; cin >> x; return x; }

int prev[M], mark[N], head[N], from[M], cap[M], to[M], ec, a[N][N], b[N][N], red[N][N], block[N][N], dis[N][N], cnt, dred[N], seen[N];
pair<int, int> q[N];
int dx[4] = {0, -1, 0, 1};
int dy[4] = {1, 0, -1, 0};

void add_edge(int u, int v, int uv, int vu) {
	from[ec] = u, to[ec] = v, cap[ec] = uv, prev[ec] = head[u], head[u] = ec++;
	from[ec] = v, to[ec] = u, cap[ec] = vu, prev[ec] = head[v], head[v] = ec++;
}

int dfs(int v, int sink, int flow = 2e9) {
	if (v == sink)
		return flow;
	if (mark[v]++)
		return 0;
	for (int e = head[v]; ~e; e = prev[e]) if (cap[e]) {
		int u = to[e];
		int x = dfs(u, sink, min(flow, cap[e]));
		if (x) {
			cap[e] -= x;
			cap[e ^ 1] += x;
			return x;
		}
	}
	return 0;
}

int max_flow(int source, int sink) {
	int res = 0;
	while (true) {
		memset(mark, 0, sizeof mark);
		int add = dfs(source, sink);
		res += add;
		if (!add)
			break;
	}
	return res;
}

int32_t main() {
	ios_base :: sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n = read(), dt = read();
	memset(head, -1, sizeof head);
	memset(dis, 63, sizeof dis);
	rep(i, N)
		dis[i][i] = 0;
	rep(x, n)
		rep(y, n) {
			char foo;
			cin >> foo;
			if (foo == 'Y')
				block[x][y] = 1;
			else if (foo == 'Z')
				red[x][y] = 1;
			else
				a[x][y] = foo - '0';
		}
	rep(x, n)
		rep(y, n) {
			char foo;
			cin >> foo;
			if (foo != 'Y' && foo != 'Z') {
				b[x][y] = foo - '0';
				rep(d, 4) {
					int i = x + dx[d], j = y + dy[d];
					if (i >= 0 && j >= 0 && i < n && j < n && !block[i][j] && !red[i][j]) {
						dis[x * n + y][i * n + j] = 1;
					}
				}
			}
		}
	int m = n * n;
	rep(k, m)
		rep(i, m)
			rep(j, m)
				if (dis[i][k] + dis[k][j] < dis[i][j])
					dis[i][j] = dis[i][k] + dis[k][j];
	int h = 0, t = 0;
	memset(dred, 63, sizeof dred);
	rep(i, n)
		rep(j, n)
			if (red[i][j]) {
				q[t++] = {i, j};
				dred[i * n + j] = 0;
			}
	while (h != t) {
		auto cur = q[h++];
		int x = cur.first, y = cur.second;
		rep(d, 4) {
			int i = x + dx[d], j = y + dy[d];
			if (i >= 0 && j >= 0 && i < n && j < n && !block[i][j] && !red[i][j] && dred[i * n + j] > 1e9) {
				dred[i * n + j] = dred[x * n + y] + 1;
				q[t++] = {i, j};
			}
		}
	}
	int sink = N - 1, source = N - 2;
	rep(cur, m) {
		memset(seen, 0, sizeof seen);
		h = 0;
		t = 0;
		int sx = cur / n, sy = cur % n;
		if (block[sx][sy] || red[sx][sy])
			continue;
		q[t++] = {sx, sy};
		seen[cur] = 1;
		while (h != t) {
			int x = q[h].first, y = q[h++].second;
			if (dis[cur][x * n + y] <= dt)
				add_edge(cur << 1, (x * n + y) << 1 | 1, 1000, 0);
			if (dis[cur][x * n + y] == dred[x * n + y])
				continue;
			rep(d, 4) {
				int i = x + dx[d], j = y + dy[d], id = i * n + j;
				if (i >= 0 && j >= 0 && i < n && j < n && !block[i][j] && !red[i][j] && dis[cur][id] <= dred[id] && dis[cur][id] <= dt && dis[cur][id] > dis[cur][x * n + y] && !seen[id]) {
					q[t++] = {i, j};
					seen[id] = 1;
				}
			}
		}
	}
	rep(i, m)
		add_edge(source, i << 1, a[i / n][i % n], 0);
	rep(i, m)
		add_edge(i << 1 | 1, sink, b[i / n][i % n], 0);
	cout << max_flow(source, sink);
}


#include <bits/stdc++.h>

using namespace std;

#define pii pair<int, int>
#define MP make_pair
#define LL long long
#define ls (i << 1)
#define rs (ls | 1)
#define md (ll + rr >> 1)
#define lson ll, md, ls
#define rson md + 1, rr, rs
#define eps 1e-8
#define inf 0x3f3f3f3f
#define mod 1000000007
#define N 410
#define M 200020
#define fi first
#define se second

char buf[32000000],*pt = buf,*o = buf;
int getint(){
    int f = 1,x = 0;
    while((*pt != '-') && (*pt < '0' || *pt > '9'))    pt ++;
    if(*pt == '-')    f = -1,pt ++;    else    x = *pt++ - 48;
    while(*pt >= '0' && *pt <= '9')    x = x * 10 + *pt ++ - 48;
    return x * f;
}
char getch(){
    char ch;
    while(*pt < 'A' || *pt > 'Z')    pt ++;
    ch=*pt;pt++;
    return ch;
}

struct dinic{
	int fst[N], vv[M], nxt[M], cap[M], flow[M], e;
	int d[N], cur[N];
	int s, t;
	void init(){
		memset(fst, -1, sizeof fst); e = 0;
	}
	void add(int u, int v, int c){
		vv[e] = v, nxt[e] = fst[u], cap[e] = c, flow[e] = 0, fst[u] = e++;
		vv[e] = u, nxt[e] = fst[v], cap[e] = 0, flow[e] = 0, fst[v] = e++;
	}
	bool bfs(){
	   	memset(d, -1, sizeof d);
   	   	d[s] = 0;
		queue<int> q;
		q.push(s);
		while(!q.empty()){
			int u = q.front(); q.pop();
			for(int i = fst[u]; ~i; i = nxt[i]){
				int v = vv[i];
				if(d[v] == -1 && cap[i] > flow[i]){
					d[v] = d[u] + 1;
					q.push(v);
				}
			}
		}
		return d[t] != -1;
	}
	int dfs(int u, int a){
		if(u == t || a == 0) return a;
		int ret = 0, f;
		for(int &i = cur[u]; ~i; i = nxt[i]){
			int v = vv[i];
			if(d[v] == d[u] + 1 && (f = dfs(v, min(a, cap[i] - flow[i]))) > 0){
				a -= f;
				ret += f;
				flow[i] += f;
				flow[i^1] -=f;
				if(a == 0) break;
			}
		}
		return ret;
	}
	int gao(int _s, int _t){
		s = _s, t = _t;
		int ret = 0;
		while(bfs()){
			memcpy(cur, fst, sizeof fst);
			ret += dfs(s, inf);
		}
		return ret;
	}
}go;
int d[4][2] = {-1, 0, 0, 1, 1, 0, 0, -1};
int dis[12][12], tim[12][12];
char g[N][N], h[N][N];
int n, t;
bool in(int x, int y){
	return x >= 0 && x < n && y >= 0 && y < n;
}
void bfs1(int sx, int sy){
	memset(tim, 0x3f, sizeof tim);
	queue<int> q;
	q.push(sx * 10 + sy);
	tim[sx][sy] = 0;
	while(!q.empty()){
		int x = q.front() / 10, y = q.front() % 10;
	   	q.pop();
		for(int i = 0; i < 4; ++i){
			int nx = x + d[i][0], ny = y + d[i][1];
			if(in(nx, ny) && g[nx][ny] >= '0' && g[nx][ny] <= '9' && tim[nx][ny] > tim[x][y] + 1){
				tim[nx][ny]	= tim[x][y] + 1;
				q.push(nx * 10 + ny);
			}
		}
	}
}
void bfs2(int sx, int sy){
	memset(dis, 0x3f, sizeof dis);
	queue<int> q;
	q.push(sx * 10 + sy);
	dis[sx][sy] = 0;
	while(!q.empty()){
		int x = q.front() / 10, y = q.front() % 10;
		q.pop();
		for(int i = 0; i < 4; ++i){
			int nx = x + d[i][0], ny = y + d[i][1];
			if(in(nx, ny) && h[nx][ny] >= '0' && h[nx][ny] <= '9' && dis[nx][ny] > dis[x][y] + 1){
				if(h[nx][ny] >= '0' && tim[nx][ny] >= dis[x][y] + 1){
					dis[nx][ny] = dis[x][y] + 1;
					if(tim[nx][ny] > dis[nx][ny])
						q.push(nx * 10 + ny);
				}
			}
		}
	}
}
int main(){
	scanf("%d%d", &n, &t);
	for(int i = 0; i < n; ++i)
		scanf("%s", g[i]);
	for(int i = 0; i < n; ++i)
		scanf("%s", h[i]);
	for(int i = 0; i < n; ++i)
		for(int j = 0; j < n; ++j)
			if(g[i][j] == 'Z')
				bfs1(i, j);
	int S = 0, T = n * n * 2 + 1;
	go.init();
	for(int i = 0; i < n; ++i)
		for(int j = 0; j < n; ++j){
			if(g[i][j] > '0' && g[i][j] <= '9')
				go.add(S, i * n + j + 1, g[i][j] - '0');
			if(h[i][j] > '0' && h[i][j] <= '9')
				go.add(n * n + i * n + j + 1, T, h[i][j] - '0');
		}
	for(int i = 0; i < n; ++i)
		for(int j = 0; j < n; ++j)
			if(g[i][j] > '0' && g[i][j] <= '9'){
				bfs2(i, j);
				for(int x = 0; x < n; ++x)
					for(int y = 0; y < n; ++y){
						if(h[x][y] > '0' && h[x][y] <= '9' && dis[x][y] <= t){
							go.add(i * n + j + 1, n * n + x * n + y + 1, inf);
						}
					}
			}
	int ret = go.gao(S, T);
	printf("%d\n", ret);
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <deque>
using namespace std;
vector<int> e[2020];
int ir[20][20];
int sc[20][20];
int pc[20][20];
char s[20][20];
char p[20][20];
int dd[20][20];
int dx[5]={0,1,-1,0};
int dy[5]={1,0,0,-1};
vector<int> ns[20][20],np[20][20];
void ade(int a,int b)
{
    e[a].push_back(b);
    e[b].push_back(a);
}
int ds[2020];
int pa[2020];
int sp,pp;
bool bfs()
{
    deque<int> q;
    for(int i=1;i<=sp;i++)
    {
        if(pa[i]==0)
            ds[i]=0,q.push_back(i);
        else
            ds[i]=3010;
    }
    ds[0]=3010;
    while(!q.empty())
    {
        int u=q[0];
        q.pop_front();
        if(ds[u]<ds[0])
        {
            for(int i=0;i<e[u].size();i++)
            {
                int v=pa[e[u][i]];
                if(ds[v]>ds[u]+1)
                    ds[v]=ds[u]+1,q.push_back(v);
            }
        }
    }
    return ds[0]!=3010;
}
bool dfs(int x)
{
    if(x==0)
        return 1;
    for(int i=0;i<e[x].size();i++)
    {
        int u=pa[e[x][i]];
        if(ds[u]==ds[x]+1)
        {
            if(dfs(u))
            {
                pa[x]=e[x][i];
                pa[e[x][i]]=x;
                return 1;
            }
        }
    }
    return 0;
}
int hkp()
{
    int an=0;
    while(bfs())
    {
        for(int i=1;i<=sp;i++)
        {
            if(pa[i]==0)
                an+=dfs(i);
        }
    }
    return an;
}
int n,t;
void wk(int a,int b)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dd[i][j]=100000;
        }
    }
    deque<pair<int,int> > q;
    dd[a][b]=0;
    q.push_back(make_pair(a,b));
    while(!q.empty())
    {
        int x=q[0].first,y=q[0].second;
        q.pop_front();
        for(int i=0;i<np[x][y].size();i++)
            for(int j=0;j<ns[a][b].size();j++)
                ade(ns[a][b][j],np[x][y][i]);
        if(dd[x][y]==ir[x][y])
            continue;
        for(int d=0;d<4;d++)
        {
            int nx=x+dx[d];
            int ny=y+dy[d];
            if(sc[nx][ny]!=-1&&dd[nx][ny]>dd[x][y]+1&&dd[x][y]+1<=ir[nx][ny])
            {
                dd[nx][ny]=dd[x][y]+1;
                q.push_back(make_pair(nx,ny));
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            ir[i][j]=t;
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=1;i<=n;i++)
        scanf("%s",p[i]+1);
    int rx,ry;
    sp=1,pp=1000;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(s[i][j]=='Z'||s[i][j]=='Y')
                sc[i][j]=-1,ir[i][j]=0;
            if(s[i][j]=='Z')
                rx=i,ry=j,ir[i][j]=0;
            if('0'<=s[i][j]&&s[i][j]<='9')
                sc[i][j]=s[i][j]-'0';
            for(int k=0;k<sc[i][j];k++)
                ns[i][j].push_back(sp++);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if('0'<=p[i][j]&&p[i][j]<='9')
                pc[i][j]=p[i][j]-'0';
            for(int k=0;k<pc[i][j];k++)
                np[i][j].push_back(pp++);
        }
    }
    deque<pair<int,int> > q;
    q.push_back(make_pair(rx,ry));
    while(!q.empty())
    {
        rx=q[0].first,ry=q[0].second;
        q.pop_front();
        int nx,ny;
        for(int d=0;d<4;d++)
        {
            nx=rx+dx[d];
            ny=ry+dy[d];
            if(ir[nx][ny]>ir[rx][ry]+1&&sc[nx][ny]!=-1)
            {
                ir[nx][ny]=ir[rx][ry]+1;
                q.push_back(make_pair(nx,ny));
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(sc[i][j]>0)
            {
                wk(i,j);
            }
        }
    }
    printf("%d",hkp());
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 10000000
#define N 210
#define M 21000
struct Edge{
    int v,w;
}edge[M];
int adj[M],head[N],e;
void addedge(int u,int v,int w){
    edge[e].v=v;edge[e].w=w;adj[e]=head[u];head[u]=e++;
    edge[e].v=u;edge[e].w=0;adj[e]=head[v];head[v]=e++;
}
int S,T;

int dist[N],q[N*2],arc[N],gap[N],inq[N],pre[N];
int SAP(int s,int t){
    memset(arc,-1,sizeof(arc));
    memset(pre,-1,sizeof(pre));
    int qf=0,qr=0;
    q[qr++]=t;inq[t]=1;gap[0]++;dist[t]=0;
    while(qf<qr){
        int u=q[qf++];
        for(int i=head[u];i!=-1;i=adj[i])
            if(!inq[edge[i].v]){
            int v=edge[i].v;
            q[qr++]=v;
            inq[v]=1;
            dist[v]=dist[u]+1;
            gap[dist[v]]++;
            arc[v]=head[v];
        }
    }
    int low=INF,u=s,ans=0;
    pre[s]=s;
    while(dist[s]<t){
        bool flag=false;
        for(int &i=arc[u];i!=-1;i=adj[i])
            if(edge[i].w && dist[edge[i].v]+1==dist[u]){
            flag=true;
            low=min(low,edge[i].w);
            pre[edge[i].v]=u;
            u=edge[i].v;
            if(u==t){
                while(u!=s){
                    u=pre[u];
                    edge[arc[u]].w-=low;
                    edge[arc[u]^1].w+=low;
                }
                ans+=low;
                low=INF;
            }
            break;
        }
        if(flag)
            continue;
        int mindis=t+1;
        for(int i=head[u];i!=-1;i=adj[i])
            if(edge[i].w && mindis>dist[edge[i].v]){
           mindis=dist[edge[i].v];
           arc[u]=i;
        }
        gap[dist[u]]--;
        if(gap[dist[u]]==0)
            return ans;
        dist[u]=mindis+1;
        gap[dist[u]]++;
        u=pre[u];
    }
    return ans;
}

char str[12][12],str2[12][12];
int sci[12][12],ca[12][12],stone[62][12][12];
int dp[62][12][12][12][12];
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int n,t;

void expand(){
    for(int k=1;k<=t;++k)
        for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
        if(stone[k-1][i][j]==1)
            stone[k][i][j]=1;
        else if(stone[k-1][i][j]==2)
            stone[k][i][j]=2;
        else{
            int nx,ny;
            for(int z=0;z<4;++z){
                nx=i+dir[z][0];
                ny=j+dir[z][1];
                if(nx>=1&&nx<=n&&ny>=1&&ny<=n){
                    if(stone[k-1][nx][ny]==2)
                        stone[k][i][j]=2;
                }
            }
        }
    }
}
int vis[12][12];
void dfs(int x,int y,int nowx,int nowy,int k){
    vis[nowx][nowy]=1;
    dp[k][x][y][nowx][nowy]=1;
    if(k>=t || stone[k][nowx][nowy])
        return;
    int nx,ny;
    for(int z=0;z<4;++z){
        nx=nowx+dir[z][0];
        ny=nowy+dir[z][1];
        if(nx>=1&&nx<=n&&ny>=1&&ny<=n && !vis[nx][ny]){
            if(stone[k][nx][ny])
                continue;
            dfs(x,y,nx,ny,k+1);
        }
    }
}
int main (){
    scanf("%d%d",&n,&t);
    for(int i=1;i<=n;++i){
        scanf("%s",str[i]+1);
        for(int j=1;j<=n;++j){
            if(str[i][j]=='Z')
                stone[0][i][j]=2;
            else if(str[i][j]=='Y')
                stone[0][i][j]=1;
            else sci[i][j]=str[i][j]-'0';
        }
    }
    for(int i=1;i<=n;++i){
        scanf("%s",str2[i]+1);
        for(int j=1;j<=n;++j){
            if(str2[i][j]>='0' && str2[i][j]<='9')
                ca[i][j]=str2[i][j]-'0';
        }
    }

    expand();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        if(sci[i][j]){
        memset(vis,0,sizeof(vis));
        dfs(i,j,i,j,0);
    }
    for(int k=1;k<=t;++k)
        for(int x=1;x<=n;++x)
            for(int y=1;y<=n;++y)
            for(int nx=1;nx<=n;++nx)
            for(int ny=1;ny<=n;++ny)
        {
            dp[k][x][y][nx][ny]+=dp[k-1][x][y][nx][ny];
        }
    S=0;T=n*n*2+1;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        addedge(S,(i-1)*n+j,sci[i][j]);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        addedge(n*n+(i-1)*n+j,T,ca[i][j]);
    for(int x=1;x<=n;++x)
        for(int y=1;y<=n;++y)
        for(int nx=1;nx<=n;++nx)
        for(int ny=1;ny<=n;++ny)
            if(sci[x][y] && ca[nx][ny]){
        if(dp[t][x][y][nx][ny])
        addedge((x-1)*n+y,n*n+(nx-1)*n+ny,INF);
    }
    int ans=SAP(S,T);
    printf("%d\n",ans);
    return 0;
}


///****In the name of Allah, most Gracious, most Compassionate****//

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;

#define ALL(a) a.begin(), a.end()
#define FastIO ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr)
#define IN freopen("input.txt","r+",stdin)
#define OUT freopen("output.txt","w+",stdout)

#define TEST

#ifdef TEST
#define DBG(a) cout<< #a <<" --> "<<(a)<<endl;
#define NL cout<<"\n";
#else
#define DBG(a) ;
#define NL cout<<"\n";
#endif // TEST

template < class T1,class T2>
ostream &operator <<(ostream &os,const pair < T1,T2 > &p)
{
    os<<"{"<<p.first<<","<<p.second<<"}";
    return os;
}

/*
	Push Relabel O(n^3) implimentation using FIFO method to chose push vertex.
	This uses gapRelabel heuristic to fasten the process even further. If only
	the maxFlow value is required then the algo can be stopped as soon as the
	gap relabel method is called. However, to get the actual flow values in the
	edges, we need to let the algo terminate itself.

	This implimentation assumes zero based vertex indexing. Edges to the graph
	can be added using the addEdge method only. capacity for residual edges is
	set to be zero. To get the actual flow values iterate through the edges and
	check for flow for an edge with cap > 0.

	This implimentaion is superior over dinic's for graphs where graph is dense
	locally at some places and mostly sparse. For randomly generated graphs, this
	implimentation gives results within seconds for n = 10000 nodes, m = 1000000
	edges.

	Code Tested on : SPOJ FASTFLOW
	@author : triveni
*/

typedef int fType;

struct edge
{
    int from, to;
    fType cap, flow;
    edge(int from, int to, fType cap, fType flow = 0) : from(from), to(to), cap(cap), flow(flow) {}
};

struct PushRelabel
{
    int N;
    vector<edge> edges;
    vector<vector<int> > G;
    vector<int> h, inQ, count;
    vector<fType> excess;
    queue<int> Q;
    PushRelabel(int N) : N(N), count(N<<1), G(N), h(N), inQ(N), excess(N) {}

    int addEdge(int from, int to, int cap)
    {
        G[from].push_back(edges.size());
        edges.push_back(edge(from, to, cap));
        G[to].push_back(edges.size());
        edges.push_back(edge(to, from, 0));
        return G[from].back();
    }

    void enQueue(int u)
    {
        if(!inQ[u] && excess[u] > 0) Q.push(u), inQ[u] = true;
    }

    void Push(int edgeIdx)
    {
        edge & e = edges[edgeIdx];
        int toPush = min<fType>(e.cap - e.flow, excess[e.from]);
        if(toPush > 0 && h[e.from] > h[e.to])
        {
            e.flow += toPush;
            excess[e.to] += toPush;
            excess[e.from] -= toPush;
            edges[edgeIdx^1].flow -= toPush;
            enQueue(e.to);
        }
    }

    void Relabel(int u)
    {
        count[h[u]] -= 1;
        h[u] = 2*N-2;
        for (int i = 0; i < G[u].size(); ++i)
        {
            edge & e = edges[G[u][i]];
            if(e.cap > e.flow) h[u] = min(h[u], h[e.to]);
        }
        count[++h[u]] += 1;
    }

    void gapRelabel(int height)
    {
        for (int u = 0; u < N; ++u) if(h[u] >= height && h[u] < N)
            {
                count[h[u]] -= 1;
                count[h[u] = N] += 1;
                enQueue(u);
            }
    }

    void Discharge(int u)
    {
        for (int i = 0; excess[u] > 0 && i < G[u].size(); ++i)
        {
            Push(G[u][i]);
        }
        if(excess[u] > 0)
        {
            if(h[u] < N && count[h[u]] < 2) gapRelabel(h[u]);
            else Relabel(u);
        }
        else if(!Q.empty())   // dequeue
        {
            Q.pop();
            inQ[u] = false;
        }
    }

    fType getFlow(int src, int snk)
    {
        h[src] = N;
        inQ[src] = inQ[snk] = true;
        count[0] = N - (count[N] = 1);
        for (int i = 0; i < G[src].size(); ++i)
        {
            excess[src] += edges[G[src][i]].cap;
            Push(G[src][i]);
        }
        while (!Q.empty())
        {
            Discharge(Q.front());
        }
        return excess[snk];
    }
};

const int N=20+5;
const int oo=1e4+7;
int dis[N][N];
string s[N];
string t[N];
int n,k;
int dx[]= {1,0,-1,0};
int dy[]= {0,1,0,-1};

vector<pii> source,sink;

int sinkid[N][N];

void bfs(int x,int y)
{
    memset(dis, -1, sizeof dis);
    queue<pii> q;
    dis[x][y]= 0;
    q.push({x,y});

    while(!q.empty())
    {
        x=  q.front().first;
        y=  q.front().second;

        q.pop();

        for(int j=0; j<4; j++)
        {
            int xx =x+dx[j];
            int yy =y+dy[j];

            if(xx<0 or xx>= n)
                continue;
            if(yy<0 or yy>= n)
                continue;

            if(dis[xx][yy] !=-1 )
                continue;

            if(t[xx][yy]=='Y' or t[xx][yy]=='Z')
                continue;
            dis[xx][yy]= dis[x][y]+1;
            q.push({xx,yy});
        }
    }
}

int dp[65][12][12][12][12];

int pos(int t,int x0,int y0, int x,int y)
{
    if(dis[x0][y0]< t) return 0;
    if(x0==x and y0==y) return 1;

    if(t>=k) return 0;

    if(dis[x0][y0]<=t) return 0;

    if(dp[t][x0][y0][x][y]!=-1) return dp[t][x0][y0][x][y];

    for(int j=0; j<4; j++)
    {
        int xx = x0+dx[j];
        int yy = y0+dy[j];

        if(xx<0 or xx>= n)
            continue;
        if(yy<0 or yy>= n)
            continue;
        if(s[xx][yy]=='Y') continue;
        if(s[xx][yy]=='Z') continue;

        if(pos(t+1 , xx ,yy , x , y)) return dp[t][x0][y0][x][y]=1;
    }
    return dp[t][x0][y0][x][y]=0;
}

int32_t main()
{
    //FastIO;

    memset(dp , -1 , sizeof dp);
    cin>>n>>k;
    for(int i=0; i<n; i++)
        cin>>s[i];
    for(int i=0; i<n; i++)
        cin>>t[i];
    int x= -1, y = -1 ;
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
            if(t[i][j]== 'Z')
                x= i, y = j;
    }
    bfs(x,y);
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++) dis[i][j] = dis[i][j]==-1 ? oo : dis[i][j];
    }

//    for(int i=0; i<n; i++)
//    {
//        for(int j=0; j<n; j++)
//            printf("%7d ",dis[i][j]);
//        NL;
//    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            char c = s[i][j];
            if(c=='Z')
                continue;
            if(c=='Y')
                continue;
            if(c=='0')
                continue;
            source.push_back({i,j});
        }
    }
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
        {
            char c = t[i][j];
            if(c=='Z')
                continue;
            if(c=='Y')
                continue;
            if(c=='0')
                continue;
            sink.push_back({i,j});
        }
    }
//    DBG(source.size());
//    DBG(sink.size());

//    for(pii i: source )
//    {
//        for(pii j: sink)
//        {
//            if(pos(0 , i.first  , i.second , j.first , j.second))  { DBG(i);DBG(j);NL; }
//        }
//    }
    PushRelabel g(source.size()  + sink.size()  + 2);
    for(int i=0;i<source.size();i++) g.addEdge(0,i+1 , s[source[i].first][source[i].second]-'0');
    for(int i=0;i<sink.size();i++) g.addEdge(source.size() + i+1  ,source.size()  + sink.size()  + 1,  t[sink[i].first][sink[i].second]-'0');
    for(int i=0;i<source.size();i++)
    {
        for(int j=0;j<sink.size();j++)
        {
            if(pos(0,source[i].first  , source[i].second , sink[j].first , sink[j].second))
                g.addEdge(i+1 , source.size()+j+1 , oo);
        }
    }
    cout<<g.getFlow(0,source.size() + sink.size() + 1);
}


/****************************************
**     Solution by Bekzhan Kassenov    **
****************************************/

#include <bits/stdc++.h>

using namespace std;

#define F first
#define S second
#define MP make_pair
#define all(x) (x).begin(), (x).end()

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

const double EPS = 1e-9;
const double PI = acos(-1.0);
const int MOD = 1000 * 1000 * 1000 + 7;
const int INF = 2000 * 1000 * 1000;
const int MAXN = 210;
const int MAXM = 2 * MAXN * MAXN;
const int dx[] = {1, 0, 0, -1};
const int dy[] = {0, 1, -1, 0};
const int S = MAXN - 2;
const int T = MAXN - 1;

template <typename T>
inline T sqr(T n) {
    return n * n;
}

struct MaxFlow {
    int to[MAXM];
    int flow[MAXM], cap[MAXM];
    int lastEdge;

    vector <int> g[MAXN];

    bool used[MAXN];

    MaxFlow() : lastEdge(0) { }

    void addEdge(int from, int to, int cap) {
        this->to[lastEdge] = to;
        this->flow[lastEdge] = 0;
        this->cap[lastEdge] = cap;
        g[from].push_back(lastEdge++);

        this->to[lastEdge] = from;
        this->flow[lastEdge] = 0;
        this->cap[lastEdge] = 0;
        g[to].push_back(lastEdge++);
    }

    bool dfs(int v, int T, int curFlow) {
        if (v == T) {
            return true;
        }

        used[v] = true;

        for (int idx: g[v]) {
            if (!used[to[idx]] && cap[idx] - flow[idx] >= curFlow &&
                dfs(to[idx], T, curFlow)) {

                flow[idx] += curFlow;
                flow[idx ^ 1] -= curFlow;

                return true;
            }
        }

        return false;
    }

    int getMaxFlow(int S, int T) {
        int curFlow = 1 << 30;
        int resFlow = 0;

        while (curFlow > 0) {
            if (dfs(S, T, curFlow)) {
                resFlow += curFlow;
            } else {
                curFlow >>= 1;
            }

            memset(used, false, sizeof used);
        }

        return resFlow;
    }
};

MaxFlow maxFlow;

int n, t;
char a[15][15];
char b[15][15];
int dist[15][15];
bool used[15][15];

bool ok(int x, int y) {
    return 0 <= x && x < n &&
           0 <= y && y < n &&
           a[x][y] != 'Y' &&
           a[x][y] != 'Z';
}

void bfsDeath(int x, int y) {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            dist[i][j] = INF;
        }
    }

    queue <int> X, Y;
    dist[x][y] = 0;
    X.push(x);
    Y.push(y);

    while (!X.empty()) {
        assert(!Y.empty());

        int curx = X.front();
        int cury = Y.front();

        X.pop();
        Y.pop();

        for (int k = 0; k < 4; k++) {
            int tx = curx + dx[k];
            int ty = cury + dy[k];

            if (ok(tx, ty) && dist[tx][ty] == INF) {
                dist[tx][ty] = dist[curx][cury] + 1;
                X.push(tx);
                Y.push(ty);
            }
        }
    }
}

void runBFS(int x, int y) {
    queue <int> X, Y, lev;
    memset(used, false, sizeof used);

    used[x][y] = true;
    X.push(x);
    Y.push(y);
    lev.push(0);

    while (!X.empty()) {
        assert(!Y.empty());

        int curx = X.front();
        int cury = Y.front();
        int curlev = lev.front();

        X.pop();
        Y.pop();
        lev.pop();

        if (isdigit(b[curx][cury]) && b[curx][cury] != '0') {
            maxFlow.addEdge(x * n + y, sqr(n) + 1 + curx * n + cury, INF);
        }

        if (curlev >= t) {
            continue;
        }

        for (int k = 0; k < 4; k++) {
            int tx = curx + dx[k];
            int ty = cury + dy[k];

            if (ok(tx, ty) && !used[tx][ty]) {
                if (dist[tx][ty] > curlev + 1) {
                    X.push(tx);
                    Y.push(ty);

                    lev.push(curlev + 1);
                } else if (dist[tx][ty] > curlev && isdigit(b[tx][ty]) && b[tx][ty] != '0') {
                    maxFlow.addEdge(x * n + y, sqr(n) + 1 + tx * n + ty, INF);
//                    printf("(%d, %d) --> (%d, %d)\n", x, y, tx, ty);
                }

                used[tx][ty] = true;
            }
        }
    }
}

void build() {

    int posi = -1, posj = -1;
    for (int i = 0; i < n && posi == -1; i++) {
        for (int j = 0; j < n && posi == -1; j++) {
            if (a[i][j] == 'Z') {
                posi = i, posj = j;
            }
        }
    }

    bfsDeath(posi, posj);

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (isdigit(a[i][j]) && a[i][j] != '0') {
                maxFlow.addEdge(S, i * n + j, a[i][j] - '0');
            }
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (isdigit(b[i][j]) && b[i][j] != '0') {
                maxFlow.addEdge(i * n + j + sqr(n) + 1, T, b[i][j] - '0');
            }
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (isdigit(a[i][j]) && a[i][j] != '0') {
                runBFS(i, j);
            }
        }
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in", "r", stdin);
#endif

    scanf("%d %d", &n, &t);

    scanf("\n");
    for (int i = 0; i < n; i++) {
        gets(a[i]);
    }

    scanf("\n");
    for (int i = 0; i < n; i++) {
        gets(b[i]);
    }

    build();

    printf("%d\n", maxFlow.getMaxFlow(S, T));

    return 0;
}


#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <deque>
#include <assert.h>
#include <bitset>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <tuple>
#include <stdio.h>
#include <string.h>
#include <utility>
#include <math.h>
using namespace std;

inline int in(){int32_t x ; scanf("%d",&x) ; return x ; }
inline string get(){char ch[1001000] ; scanf("%s",ch) ; return ch;}
template<class P, class Q> inline P smin(P &a, Q b) { if (b < a) a = b; return a; }
template<class P, class Q> inline P smax(P &a, Q b) { if (a < b) a = b; return a; }
#define mp make_pair
#define EPS 1e-9
//#define int long long
typedef pair<int , int > pii;
typedef long double ld;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e5 + 10;
const int base = 29;
const int MAX_LG = 21;
const int mod = 1e9 + 7;
const int INF = 1e18;
int n , t;
string a[30] , b[30];
int dist1[30][30] , dist2[30][30];
int dx[] = {0,0,-1,1};
int dy[] = {1,-1,0,0};
struct edge
{
    int a , b , cap , flow;
};
int di[maxn];
int ptr[maxn];
int q[maxn];
vector<edge> e;
vector<int> g[maxn];
int whereX , whereY;
int source , sink;
inline void add(int a , int b , int cap)
{
    edge e1 = {a,b,cap,0};
    edge e2 = {b,a,0,0};
    g[a].push_back((int)e.size());
    e.push_back(e1);
    g[b].push_back((int)e.size());
    e.push_back(e2);
}
inline bool ok(int x , int y){return (x >= 0 && x < n && y >= 0 && y < n);}
inline void BFS1(int x = whereX , int y = whereY)
{
    queue<pii> q;
    q.push({x,y});
    for (int i = 0 ; i <= 20 ; i ++)
        for (int j = 0 ; j <= 20 ; j ++)
            dist1[i][j] = 1e9;
    dist1[x][y] = 0;
    while (!q.empty())
    {
        int x = q.front().first , y = q.front().second;
        q.pop();
        for (int i = 0 ; i < 4 ; i ++)
        {
            int x2 = x + dx[i] , y2 = y + dy[i];
            if (ok(x2,y2) && dist1[x2][y2] >= 1e9 && b[x2][y2] != 'Y')
            {
                dist1[x2][y2] = dist1[x][y] + 1;
                q.push({x2,y2});
            }
        }
    }

}
inline bool bfs()
{
    memset(di,-1,n * sizeof di[0]);
    int qh = 0 , qt = 0;
    q[qt ++] = source;
    di[source] = 0;
    while (qh < qt && di[sink] == -1)
    {
        int v = q[qh ++];
        for (int pt = 0 ; pt < g[v].size() ; pt ++)
        {
            int id = g[v][pt] , to = e[id].b;
            if (di[to] == -1 && e[id].flow < e[id].cap)
            {
                q[qt ++] = to;
                di[to] = di[v] + 1;
            }
        }
    }
    return di[sink] != -1;
}
inline int dfs(int v , int flow)
{
    if (!flow) return 0;
    if (v == sink) return flow;
    for ( ; ptr[v] < g[v].size() ; ptr[v] ++)
    {
        int id = g[v][ptr[v]] , to = e[id].b;
        if (di[to ] != di[v] + 1) continue;
        int pushed = dfs(to , min(flow , e[id].cap - e[id].flow));
        if (pushed)
        {
            e[id].flow += pushed;
            e[id^1].flow -= pushed;
            return pushed;
        }
    }
    return 0;
}
inline int max_flow()
{
    int flow = 0;
    while (true)
    {
        if (!bfs()) break;
        memset(ptr,0,n * sizeof ptr[0]);
        while (int pushed = dfs(source , 1e9))
        {
            flow += pushed;
        }
    }
    return flow;
}
inline void BFS2(int x , int y)
{
    queue<pii> q;
    q.push({x,y});
    for (int i = 0 ; i <= 20 ; i ++)
        for (int j = 0 ; j <= 20 ; j ++)
            dist2[i][j] = 1e9;
    dist2[x][y] = 0;
    while (!q.empty())
    {
        int x = q.front().first , y = q.front().second;
        q.pop();
        if (dist2[x][y] >= dist1[x][y]) continue;
        for (int i = 0 ; i < 4 ; i++)
        {
            int x2 = x + dx[i] , y2 = y + dy[i];
            if(ok(x2,y2) &&  dist2[x2][y2] >= 1e9 && a[x2][y2] != 'Y' && dist2[x][y] + 1 <= dist1[x2][y2])
            {
                dist2[x2][y2] = dist2[x][y] + 1;
                q.push({x2,y2});
            }
        }
    }
}
int32_t main()
{
    n = in() , t = in();
    for (int i = 0 ; i < n ; i ++)
        a[i] = get();
    for (int i = 0 ; i < n ; i ++)
    {
        b[i] = get();
        for (int j = 0 ; j < n ; j ++)
        {
            if (b[i][j] == 'Z')
            {
                b[i][j] = a[i][j] = 'Y';
                whereX = i , whereY = j;
            }
        }
    }
    BFS1();
    source = 0 , sink = 2 * n * n + 1;
    for (int i = 0 ; i < n ; i ++)
    {
        for (int j = 0 ; j < n ; j ++)
        {
            if (a[i][j] == 'Y') continue;
            int what = i * n + j + 1;
            int what2 = n * n + i * n + j + 1;
            add(source,what,a[i][j]-'0');
            add(what2,sink,b[i][j]-'0');
            BFS2(i , j);
            for (int ptx = 0 ; ptx < n ; ptx ++)
            {
                for (int pty = 0 ; pty < n ; pty ++)
                {
                    if (b[ptx][pty] == 'Y' || dist2[ptx][pty] > t) continue;
                    add(what,n * n + ptx * n + pty + 1 , a[i][j] - '0');
                }
            }
        }
    }
    n = 2 * n * n + 5;

//    printf("%d\n",max_flow());
    cout << max_flow() << endl;
}


#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <queue>

using namespace std;

struct node
{
  int r,c,dis;
};

const int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
queue<node> q;
char s[15];
int n,n1,m,lim,tot,p,a[11][11],b[11][11],d0[11][11],f[202][202],d[202][202],w[202],h[202],g[203];
bool t,flag,ok[12][12],okb[12][12];

void search(int x,int z)
{
  if(x==n+1)
  {
    p=z;
    flag=true;
    return;
  }
  int temp=n+2;
  for(int y=0;y<=n+1;++y)
  {
    if(d[x][y]<f[x][y])
    {
      temp=min(temp,h[y]);
      if(h[x]==h[y]+1)
      {
        w[++tot]=y;
        search(y,min(z,f[x][y]-d[x][y]));
        if((!t)||(flag))
          return;
        w[tot--]=0;
      }
    }
    if(d[y][x]>0)
    {
      temp=min(temp,h[y]);
      if(h[x]==h[y]+1)
      {
        w[++tot]=-y;
        search(y,min(z,d[y][x]));
        if((!t)||(flag))
          return;
        w[tot--]=0;
      }
    }
  }
  if(temp+1!=h[x])
  {
    --g[h[x]];
    if(g[h[x]]==0)
      t=false;
    h[x]=temp+1;
    ++g[h[x]];
  }
}

bool improvable()
{
  flag=false;
  p=n1;
  tot=0;
  w[0]=0;
  search(0,n1);
  return flag;
}

void improve()
{
  for(int x=1;x<=tot;++x)
  {
    if(w[x]>0)
      d[abs(w[x-1])][w[x]]+=p;
    else
      d[-w[x]][abs(w[x-1])]-=p;
  }
}

int main(void)
{
  scanf("%d %d",&m,&lim);
  for(int i=1;i<=m;++i)
  {
    scanf("%s",s+1);
    for(int j=1;j<=m;++j)
    {
      if(s[j]=='Z')
      {
        node he;
        he.r=i;
        he.c=j;
        he.dis=0;
        q.push(he);
      }
      else if(s[j]!='Y')
      {
        ok[i][j]=true;
        d0[i][j]=lim;
        int k=s[j]-'0';
        if(k>0)
        {
          a[i][j]=++n;
          f[0][n]=k;
          n1+=k;
        }
      }
    }
  }
  memcpy(okb,ok,sizeof(ok));
  for(int i=1;i<=m;++i)
  {
    scanf("%s",s+1);
    for(int j=1;j<=m;++j)
    {
      if((s[j]=='Z')||(s[j]=='Y'))
        continue;
      int k=s[j]-'0';
      if(k>0)
      {
        b[i][j]=++n;
        f[n][m*m+1]=k;
      }
    }
  }
  if(n!=m*m)
  {
    for(int i=1;i<=m;++i)
    {
      for(int j=1;j<=m;++j)
      {
        if(b[i][j]>0)
        {
          int k=b[i][j];
          f[k][n+1]=f[k][m*m+1];
          f[k][m*m+1]=0;
        }
      }
    }
  }
  while(!q.empty())
  {
    node he=q.front();
    q.pop();
    int i=he.r,j=he.c;
    d0[i][j]=he.dis;
    for(int k=0;k<4;++k)
    {
      if(ok[i+dx[k]][j+dy[k]])
      {
        node e;
        e.r=i+dx[k];
        e.c=j+dy[k];
        e.dis=he.dis+1;
        q.push(e);
        ok[i+dx[k]][j+dy[k]]=false;
      }
    }
  }
  for(int i=1;i<=m;++i)
  {
    for(int j=1;j<=m;++j)
    {
      if(a[i][j]==0)
        continue;
      memcpy(ok,okb,sizeof(okb));
      ok[i][j]=false;
      node he;
      he.r=i;
      he.c=j;
      he.dis=0;
      q.push(he);
      while(!q.empty())
      {
        node he=q.front();
        q.pop();
        int x=he.r,y=he.c;
        if((b[x][y]>0)&&(he.dis<=d0[x][y]))
          f[a[i][j]][b[x][y]]=n1;
        if((he.dis+1>lim)||(he.dis>=d0[x][y]))
          continue;
        for(int k=0;k<4;++k)
        {
          if(ok[x+dx[k]][y+dy[k]])
          {
            node e;
            e.r=x+dx[k];
            e.c=y+dy[k];
            e.dis=he.dis+1;
            q.push(e);
            ok[x+dx[k]][y+dy[k]]=false;
          }
        }
      }
    }
  }
  g[0]=n+2;
  t=true;
  while((t)&&(h[0]<=n+2))
    while(improvable())
      improve();
  int ans=0;
  for(int i=1;i<=n;++i)
    ans+=d[i][n+1];
  printf("%d\n",ans);
  return 0;
}


#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
#define rep(i,n) for(int i = 0;i < n;i ++)

template<int N>
struct MaxFlow {
	int l[N], tot, cur[N], d[N], u, v, s, t, src, sink;

	struct Edge {
		int v, x, cap;
	} E[111111];

	void add(int u, int v, int cap) {
		E[tot] = (Edge) {v, l[u], cap};
		l[u] = tot ++;
		E[tot] = (Edge) {u, l[v], 0};
		l[v] = tot ++;
	}

	void init() {
		memset(l, -1, sizeof l);
		tot = 0;
	}

	bool bfs() {
		memset(d, -1, sizeof d);
		memcpy(cur, l, sizeof l);
		d[src] = 0;
		queue<int> Q;
		Q.push(src);
		while(!Q.empty()) {
			u = Q.front();
			Q.pop();
			for(int i = l[u]; ~i; i = E[i].x) {
				v = E[i].v;
				if(d[v] == - 1 && E[i].cap) {
					d[v] = d[u] + 1;
					Q.push(v);
				}
			}
		}
		return d[sink] != -1;
	}

	int dfs(int u, int in) {
		if(u == sink)	return in;
		int flow = 0, f;
		for(int &i = cur[u]; ~i; i = E[i].x) {
			v = E[i].v;
			if(d[v] == d[u] + 1 && E[i].cap) {
				if(f=dfs(v, min(in-flow, E[i].cap))) {
					flow += f;
					E[i].cap -= f;
					E[i^1].cap += f;
					if(flow == in)	break;
				}
			}
		}
		if(flow < in)	d[u] = -1;
		return flow;
	}

	const int inf = 1e9;
	int dinic(int _src, int _sink) {
		src = _src, sink = _sink;
		int flow = 0;
		while(bfs())
			flow += dfs(src, inf);
		return flow;
	}
};

int n;

const int N = 15;
char field[N][N], capsule[N][N];
int Z[N][N], S[N][N];
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

inline bool In(int i, int j) {
	return i>=0&&i<n&&j>=0&&j<n;
}
MaxFlow<210> F;

int t;
const int inf = 1e9;
inline bool isdigit(char ch) {
	return ch>='1' && ch <='9';
}
void bfs(int x, int y, int d[][N], bool f) {
	int sx = x, sy = y;
	fill(d[0], d[N], inf);
	d[x][y] = 0;
	queue<int> Q;
	Q.push(x);
	Q.push(y);
	if(f && isdigit(capsule[x][y])) {
		F.add(sx*n+sy, sx*n+sy+n*n, inf);
	}
	while(!Q.empty()) {
		x = Q.front();
		Q.pop();
		y = Q.front();
		Q.pop();
		if(d[x][y] == t)	break;
		rep(o, 4) {
			int xx = x + dx[o];
			int yy = y + dy[o];
			if(In(xx, yy) && d[xx][yy] == inf && capsule[xx][yy] != 'Y') {
				if(Z[xx][yy] > d[x][y] + 1 || Z[xx][yy] == d[x][y] + 1 && isdigit(capsule[xx][yy])) {
					d[xx][yy] = d[x][y] + 1;
					if(f && isdigit(capsule[xx][yy])) {
						F.add(sx*n+sy, xx*n+yy+n*n, inf);
					}
					if(Z[xx][yy] > d[x][y] + 1 || !f) {
						Q.push(xx);
						Q.push(yy);
					}
				}
			}
		}
	}
}

int main() {
	int x, y;
	scanf("%d%d", &n, &t);
	int src = n*n*2, sink = src + 1;
	F.init();
	rep(i, n) {
		scanf("%s", field[i]);
		rep(j, n) {
			if(field[i][j] == 'Z') {
				x = i, y = j;
			}
		}
	}
	rep(i, n) {
		scanf("%s", capsule[i]);
		rep(j, n) {
			if(isdigit(capsule[i][j])) {
				F.add(i*n+j+n*n, sink, capsule[i][j]-'0');
			}
		}
	}
	bfs(x, y, Z, false);
	rep(i, n) {
		rep(j, n) {
			if(isdigit(field[i][j])) {
				F.add(src, i*n+j, field[i][j]-'0');
				bfs(i, j, S, true);
			}
		}
	}
	printf("%d\n", F.dinic(src, sink));
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

// Graph stuff from TCR:
struct Edge {       /* Directed edge */
  int from;      /* Index of the source node */
  int to;        /* Index of the destination node */
  double length; /* Length of the edge */
  Edge(int f, int t, double l): from(f), to(t), length(l) {}
};

struct Node {
  vector<int> out; /* Indices of edges that start in this node */
};

struct Graph {         /* Directed graph */
  vector<Node> nodes; /* List of nodes */
  vector<Edge> edges; /* List of edges */

  Graph(int nr_nodes, int nr_edges)
  {
    nodes.resize(nr_nodes);  /* Create nodes, without edges */
    edges.reserve(nr_edges); /* Reserve space for edges */
  }

  void add_edge(int from, int to, double length)
  {
    Edge e = Edge(from, to, length);
    edges.push_back(e); /* Add edge to the list */
    nodes[from].out.push_back(edges.size()-1); /* Add to the source node */
  }

  vector<int> find_augmenting_path(int source, int sink,
      vector<double> flow, double *path_cap)
    /* Used in the max_flow algorithm to find an augmenting path,
     * it returns the edges that are on the augmenting path, or an empty vector
     * if there is no path. The path_cap parameter will be set to the capacity
     * of the path.
     * This implementation uses priority based search to find an augmenting path
     * $O(|edges| \log |nodes|)$
     */
  {
    /* Queue that does highest priority first: */
    set< pair<double, int>, greater< pair<double,int> > > q;
    vector<double> capacity (nodes.size(), 0); /* Capacity to each node */
    vector<int> pred(nodes.size(),-1);         /* Data to find the path */
    vector<int> path;

    capacity[source]=INFINITY;             /* Infinite capacity for source */
    q.insert(make_pair(INFINITY, source)); /* Put source in the queue */

    while ((!q.empty()) && (capacity[sink] == 0)) {
      double cap = q.begin()->first;
      int n = q.begin()->second;
      q.erase(q.begin());

      for (unsigned int i = 0 ; i < nodes[n].out.size(); i++) {
        int e_idx = nodes[n].out[i];
        Edge &e = edges[e_idx];
        double e_cap = e.length - flow[e_idx];

        if ((e_cap > 0) && (min(cap,e_cap) > capacity[e.to])) {
          q.erase(make_pair(capacity[e.to], e.to));
          capacity[e.to] = min(cap,e_cap);
          q.insert(make_pair(capacity[e.to], e.to));
          pred[e.to] = e_idx;
        }
      }
    }

    /* Reconstruct the path */
    *path_cap = capacity[sink];
    {
      int e_idx = pred[sink];
      while (e_idx != -1)
      {
        path.push_back(e_idx);
        e_idx = pred[edges[e_idx].from];
      }
    }

    return path;
  }

  double max_flow(int source, int sink)
    /* Computes the maximum flow through the graph from source to sink using
     * Ford-Fulkerson, combined with a priority first search for the augmenting
     * path.
     * $O(|edges|^2 \log |nodes|)$
     */
  {
    Graph residual(nodes.size(), 2*edges.size());
    vector<double> flow(2*edges.size(), 0);
    vector<int> path;
    double path_cap;
    double max_flow = 0;

    /* Construct residual graph */
    for (unsigned int i=0; i < edges.size(); i++)
    {
      residual.add_edge(edges[i].from, edges[i].to, edges[i].length);
      residual.add_edge(edges[i].to, edges[i].from, 0);
    }

    path=residual.find_augmenting_path(source, sink, flow, &path_cap);
    while (path_cap > 0)
    {
      for (unsigned int i=0; i < path.size(); i++)
      {
        int e_idx = path[i];
        int e_ridx = e_idx + 1;
        if ((e_idx % 2) == 1) e_ridx = e_idx - 1;
        flow[e_idx] = flow[e_idx] + path_cap;
        flow[e_ridx] = flow[e_ridx] - path_cap;
      }
      path=residual.find_augmenting_path(source, sink, flow, &path_cap);
    }

    for (unsigned int i = 0 ; i < residual.nodes[source].out.size(); i++)
    {
      int e_idx = residual.nodes[source].out[i];
      max_flow = max_flow + flow[e_idx];
    }

    // Note: to find a min-cut, divide the graph into all nodes
    // that are reachable from the source via non-saturated edges
    // and those that are not. The endges between those two sets
    // of nodes will have a total capacity of max_flow

    return max_flow;
  }

  void print_all();
};

static int n;
static int t;

struct Room
{
  int i,j;
  array<bool, 61> infected;
  array<bool, 61> accessible;
  int scientists;
  int capsules;

  Room(): scientists{0}, capsules{0}
  {
    fill(infected.begin(), infected.end(), false);
    fill(accessible.begin(), accessible.end(), true);
  }

  int get_node_id(int timestamp) const
  {
    return 2 + i + n*j + (n*n)*timestamp;
  }

  void set_reactor()
  {
    fill(accessible.begin(), accessible.end(), false);
  }

  void set_infected(int timestamp = 0)
  {
    if (accessible[timestamp])
    {
      accessible[timestamp] = false;
      infected[timestamp] = true;
    }
  }

  void spread_infection(int timestamp);

};

static array< array< Room, 10>, 10> floorplan;

void Room::spread_infection(int timestamp)
{
  if (infected[timestamp])
  {
    set_infected(timestamp+1);
    if (i > 0) floorplan[i-1][j].set_infected(timestamp+1);
    if (i < (n-1)) floorplan[i+1][j].set_infected(timestamp+1);
    if (j > 0) floorplan[i][j-1].set_infected(timestamp+1);
    if (j < (n-1)) floorplan[i][j+1].set_infected(timestamp+1);
  }
}

string id_to_string(int id)
{
  if (id == 0) return "source";
  if (id == 1) return "sink";
  stringstream ss;
  int row = (id - 2) % n;
  int col = ((id - 2 - row) % (n*n)) / n;
  int timestamp = (id - 2 - row - col*n) / (n*n);
  ss << "(" << row << "," << col << "," << timestamp << ")";
  return ss.str();
}

void Graph::print_all()
{
  for (int i = 0; i < nodes.size() ; i++)
  {
    Node& node = nodes[i];
    cout << id_to_string(i) << " has edges to : ";
    for (int e = 0; e < node.out.size(); ++e) {
      cout << id_to_string(edges[node.out[e]].to) << " ";
    }
    cout << endl;
  }
}

int main (void)
{
  ios::sync_with_stdio(false);

  cin >> n >> t;

  // Read scientist locations
  for (int i = 0; i < n; i++)
  {
    string line;
    cin >> line;
    for (int j = 0; j < n; j++)
    {
      floorplan[i][j].i = i;
      floorplan[i][j].j = j;
      if (line[j] == 'Y') floorplan[i][j].set_reactor();
      else if (line[j] == 'Z') floorplan[i][j].set_infected();
      else floorplan[i][j].scientists = line[j] - '0';
    }
  }

  // Read capsule locations
  for (int i = 0; i < n; i++)
  {
    string line;
    cin >> line;
    for (int j = 0; j < n; j++)
    {
      if ((line[j] != 'Y') && (line[j] != 'Z')) floorplan[i][j].capsules = line[j] - '0';
    }
  }

  // Figure out the spread of the infection
  for (int c = 0; c <= t; c++)
  {
    for (int i = 0; i < n; i++)
    {
      for (int j = 0; j < n; j++)
      {
        if (c < t) floorplan[i][j].spread_infection(c);
        /*if (floorplan[i][j].infected[c]) cout << "I";
        else if (floorplan[i][j].accessible[c]) cout << ".";
        else cout << "X";*/
      }
      //cout << "\n";
    }
    //cout << "\n\n";
  }

  // Convert to graph
  Graph g(n*n*(t+1)+2, 100*4*60);
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < n; j++)
    {
      const Room &room = floorplan[i][j];
      if (room.scientists > 0) g.add_edge(0, room.get_node_id(0), room.scientists);
      if (room.capsules > 0) g.add_edge(room.get_node_id(t), 1, room.capsules);
      for (int c = 0; c < t; c++)
      {
        if (room.capsules > 0) g.add_edge(room.get_node_id(c), room.get_node_id(t), 1000);
        if (room.accessible[c])
        {
          if (i > 0)
          {
            const Room &other = floorplan[i-1][j];
            if (other.accessible[c]) g.add_edge(room.get_node_id(c), other.get_node_id(c+1), 1000);
          }
          if (i < (n-1))
          {
            const Room &other = floorplan[i+1][j];
            if (other.accessible[c]) g.add_edge(room.get_node_id(c), other.get_node_id(c+1), 1000);
          }
          if (j > 0)
          {
            const Room &other = floorplan[i][j-1];
            if (other.accessible[c]) g.add_edge(room.get_node_id(c), other.get_node_id(c+1), 1000);
          }
          if (j < (n-1))
          {
            const Room &other = floorplan[i][j+1];
            if (other.accessible[c]) g.add_edge(room.get_node_id(c), other.get_node_id(c+1), 1000);
          }
        }
      }
    }
  }

  //g.print_all();

  cout << int(g.max_flow(0,1)) << "\n";

  return 0;
}


#include<map>
#include<cmath>
#include<ctime>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<string.h>
//#include<windows.h>
#include<algorithm>
#define y1 abcde
#define sqr(x) ((x)*(x))
#define INF 2147483647
using namespace std;

  double ds,x[3],y[3],r[3],R[3];
  int ans;

    double dist(double x,double y,double xx, double yy)
{
      return sqrt((x - xx)*(x - xx) + (y - yy)*(y-yy));
}
int main()
{
   //srand(GetTickCount());
   #ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
   #endif

     cin>>x[1]>>y[1]>>r[1]>>R[1];
     cin>>x[2]>>y[2]>>r[2]>>R[2];

     //
     ds = dist(x[1],y[1],x[2],y[2]);
       if (ds >= R[2]+r[1]) ans++; else
       if (ds + r[1] <= r[2]) ans++; else
       if (ds + R[2] <= r[1]) ans++;

       if (ds >= R[2]+R[1]) ans++; else
       if (ds + R[1] <= r[2]) ans++; else
       if (ds + R[2] <= R[1]) ans++;

       if (ds >= r[2]+R[1]) ans++; else
       if (ds + r[2] <= r[1]) ans++; else
       if (ds + R[1] <= r[2]) ans++;

       if (ds >= R[2]+R[1]) ans++; else
       if (ds + R[2] <= r[1]) ans++; else
       if (ds + R[1] <= R[2]) ans++;
     //
     cout<<ans;
    return 0;
}


#include <bits/stdc++.h>

#define ford(i, n) for(int i = (int)(n) - 1; i >= 0; i--)
#define forn(i, n) for(int i = 0; i < (int)(n); i++)
#define for1(i, n) for(int i = 1; i <= (int)(n); i++)
#define all(x) (x).begin(), (x).end()
#define clr(x) memset((x), 0, sizeof((x)));
#define pb push_back
#define mp make_pair
#define x first
#define y second

using namespace std;
typedef long double ld;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef long long i64;
typedef unsigned long long ull;

template<class T>
bool remin(T &a, const T &b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool remax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

int nxt() {
    int x;
    scanf("%d", &x);
    return x;
}

ll gcd(ll a, ll b) {
    a = abs(a);
    b = abs(b);
    while (b) {
        a %= b;
        swap(a, b);
    }
    return a;
}

typedef ll ptdata;

struct pt {
    ptdata x, y;

    pt() {}

    pt(ptdata x, ptdata y) : x(x), y(y) {}

    inline pt operator-(const pt &r) const {
        return pt(x - r.x, y - r.y);
    }

    inline pt operator+(const pt &r) const {
        return pt(x + r.x, y + r.y);
    }

    inline pt operator*(const ld &r) const {
        return pt(x * r, y * r);
    }

    inline ptdata sqlen() const {
        return abs(x * x + y * y);
    }

    inline bool operator<(const pt &r) const {
        if (x != r.x) return x < r.x;
        return y < r.y;
    }

    inline bool operator==(const pt &r) const {
        return x == r.x && y == r.y;
    }
};

ostream &operator<<(ostream &os, const pt &p) {
    return os << "(" << p.x << "," << p.y << ")";
}

inline ptdata cross(const pt &l, const pt &r) {
    return l.x * r.y - l.y * r.x;
}

inline ptdata dot(const pt &l, const pt &r) {
    return l.x * r.x + l.y * r.y;
}

ll pwmod(ll a, ll n, ll mod) {
    ll ret = 1;
    while (n) {
        if (n & 1) ret = ret * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ret;
}

template<typename T>
inline T sqr(T x) {
    return x * x;
}

const int N = 1000 * 1000;
const ll inf = LLONG_MAX >> 1;
struct Q {
    ll q[N];
    ll sum = 0;
    int cnt[N];
    int qs = 0, qsize = 0;
    Q() {}
    inline void add(ll val, int c) {
        sum += c;
        if (empty()) {
            q[qs] = val;
            cnt[qs] = c;
            ++qsize;
            return;
        }
        if (qsize == N) return;
        int ps1 = qs + qsize - 1;
        if (ps1 >= N) ps1 -= N;
        int ps2 = qs + qsize;
        if (ps2 >= N) ps2 -= N;
        if (q[ps1] == val) {
            cnt[ps1] += c;
            return;
        }
        q[ps2] = val;
        cnt[ps2] = c;
        qsize++;
    }
    inline bool empty() const {
        return qsize == 0;
    }
    inline pair<ll, int> min() const {
        if (empty()) return mp(inf, 1);
        return mp(q[qs], cnt[qs]);
    }
    inline pair<ll, int> max() const {
        if (empty()) return mp(-inf, 1);
        int ps1 = qs + qsize - 1;
        if (ps1 >= N) ps1 -= N;
        return mp(q[ps1], cnt[ps1]);
    }
    inline void pop() {
        sum -= cnt[qs];
        ++qs;
        --qsize;
        if (qs == N) qs = 0;
    }
};

Q q[2];

const int MAGIC = 100000;

inline void solve() {
    int n = nxt();
    ll c[2];
    c[0] = nxt();
    c[1] = nxt();
    if (c[0] == 0 || c[1] == 0) {
        ll m = c[0] + c[1];
        cout << (n - 1) * m << "\n";
        return;
    }
    q[0].add(0, 1);

    ll ans = 0;
    pair<ll, int> mi[2];
    pair<ll, int> ma[2];
    --n;
    while (n > 0) {
        forn(j, 2) {
            mi[j] = q[j].min();
            ma[j] = q[j].max();
        }
        int id = 0;
        if (mi[1].first < mi[0].first) id = 1;

        ll k = n;
        if (c[id]) {
            k = (mi[id ^ 1].first - ma[id].first) / c[id];
        }
        remin(k, (n / q[id].sum));

        if (k == 0 || q[id ^ 1].qsize < MAGIC) {
            int cc = min(mi[id].second, n);
            n -= cc;
            ans -= mi[id].first * cc;
            ans += mi[id].first * cc + c[0] * cc;
            ans += mi[id].first * cc + c[1] * cc;
            mi[id].second -= cc;
            if (mi[id].second == 0) {
                q[id].pop();
            }
            q[0].add(mi[id].first + c[0], cc);
            q[1].add(mi[id].first + c[1], cc);
        } else {
//            cerr << k << "\n";
//            cerr << q[id].qsize << "\n";
            vector<pair<ll, int> > w;
            while (!q[id].empty()) {
                w.push_back(q[id].min());
                q[id].pop();
            }
            for (auto pa : w) {
                ans -= pa.first * pa.second;
            }
            for (auto pa : w) {
//                cerr << pa.first * pa.second + k * c[id] * pa.second << "\n";
//                cerr << k * pa.first * pa.second + k * (k - 1) / 2 * c[id] + k * c[id ^ 1] * pa.second << "\n";
                ans += pa.first * pa.second + k * c[id] * pa.second;
                ans += k * pa.first * pa.second + k * (k - 1) / 2 * c[id] + k * c[id ^ 1] * pa.second;
                q[id].add(pa.first + k * c[id], pa.second);
            }
            n -= k * q[id].sum;
        }
    }
    cout << ans << "\n";
}

void prepare() {

}

int main() {
#ifdef LOCAL
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#endif
    ios_base::sync_with_stdio(false);
    cin.tie(0);

    prepare();

    int t = 1;
    //t = nxt();
    forn(i, t) {
        solve();
    }
    //14999999850000000
    //195405044762803700
    //9999999999999999
    //100000000 1 100000000
    //20042860182236000
    cerr << "Time " << clock() / (double) CLOCKS_PER_SEC << endl;
    return 0;
}


//加油吧
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353,N=200200,G=3,Gi=332748118;
ll power(ll base,ll b){
	ll ret=1;
	while(b){
		if(b&1)ret=ret*base%mod;
		base=base*base%mod;
		b>>=1;
	}
	return ret;
}
int limit,len,last=-1,pos[N];
ll G0[N],G1[N],G2[N],g[N],F0[N],F1[N],F2[N];
//F0是两端都没有距离为2的点
//F1是一端有距离为2的点  (答案统计时有两种方案数相同的情况)
//F2是两端都有距离为2的点
inline void getlen(int n){
	limit=1,len=0;
	while(limit<n)limit<<=1,++len;
	if(last==limit)return;
	last=limit;
	for(int i=1;i<limit;++i)
		pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
}
inline void ntt(ll *a,int n,int type){
	for(int i=0;i<limit;++i)
		if(i<pos[i])swap(a[i],a[pos[i]]);
	for(int mid=1;mid<limit;mid<<=1){
		ll wn=power((type==1?G:Gi),(mod-1)/(mid<<1));
		for(int j=0;j<limit;j+=(mid<<1)){
			ll w=1;
			for(int k=0;k<mid;++k,w=w*wn%mod){
				ll x=a[j+k],y=a[j+mid+k]*w%mod;
				a[j+k]=(x+y)%mod;
				a[j+mid+k]=(x-y+mod)%mod;
			}
		}
	}
	if(type==-1){
		ll inv=power(limit,mod-2);
		for(int i=0;i<n;++i)a[i]=a[i]*inv%mod;
		for(int i=n;i<limit;++i)a[i]=0;
	}
}
ll f[N],h[N],tmp[N];
void calc(ll *a,int n,ll *b,int m,ll *c,int nm=-1){
	if(nm==-1)nm=n+m-1;
	getlen(nm);
	for(int i=0;i<n;++i)f[i]=a[i];
	for(int i=n;i<limit;++i)f[i]=0;
	for(int i=0;i<m;++i)h[i]=b[i];
	for(int i=m;i<limit;++i)h[i]=0;
	ntt(f,nm,1),ntt(h,nm,1);
	for(int i=0;i<limit;++i)f[i]=f[i]*h[i]%mod;
	ntt(f,nm,-1);
	for(int i=0;i<nm;++i)c[i]=f[i];
}
void CDQ(int l,int r){
	if(l==r){
		F0[l]=(F0[l]+G0[l])%mod;
		F1[l]=(F1[l]+G1[l])%mod;
		F2[l]=(F2[l]+G2[l])%mod;
		return;
	}
	int mid=(l+r)>>1;
	CDQ(l,mid);
	calc(F0+l,mid-l+1,G0,r-l+1,tmp+l,r-l+1);
	for(int i=mid+1;i<=r;++i)F0[i]=(F0[i]+tmp[i])%mod;
	calc(F0+l,mid-l+1,G1,r-l+1,tmp+l,r-l+1);
	for(int i=mid+1;i<=r;++i)F1[i]=(F1[i]+tmp[i])%mod;
	calc(F1+l,mid-l+1,G1,r-l+1,tmp+l,r-l+1);
	for(int i=mid+1;i<=r;++i)F0[i]=(F0[i]+tmp[i])%mod;
	for(int i=mid+1;i<=r;++i)F2[i]=(F2[i]+tmp[i])%mod;
	calc(F1+l,mid-l+1,G2,r-l+1,tmp+l,r-l+1);
	for(int i=mid+1;i<=r;++i)F1[i]=(F1[i]+tmp[i])%mod;
	calc(F2+l,mid-l+1,G2,r-l+1,tmp+l,r-l+1);
	for(int i=mid+1;i<=r;++i)F2[i]=(F2[i]+tmp[i])%mod;
	//注意是左边对右边的贡献
	CDQ(mid+1,r);
}
int n;
int main(){
//	freopen("y.in","r",stdin);
	scanf("%d",&n);
	g[0]=g[2]=1;
	for(int i=4;i<=n;++i)g[i]=(g[i-2]+g[i-4])%mod;
	for(int i=1;i<=n;++i)G0[i]=1LL*(i-1)*(i-1)%mod*g[i-1]%mod;
	for(int i=2;i<=n;++i)G1[i]=1LL*(i-1)*(i-1)%mod*g[i-2]%mod;
	for(int i=3;i<=n;++i)G2[i]=1LL*(i-1)*(i-1)%mod*g[i-3]%mod;
	CDQ(1,n);
	ll Ans=1LL*n*(G0[n]+G2[n])%mod;//可以旋转n次
	for(int i=2;i<=n-2;++i){
		Ans=(Ans+(G0[i]*F0[n-i]%mod+2LL*G1[i]*F1[n-i]%mod+G2[i]*F2[n-i]%mod)*(ll)i%mod)%mod;//把第一个相对的点对旋转到1-n+1处
	}
	printf("%lld\n",(Ans%mod+mod)%mod);
	return 0;
}


//khodaya khodet komak kon
#include <bits/stdc++.h>

#define F first
#define S second
#define pb push_back
#define all(x) x.begin(), x.end()
#pragma GCC optimize ("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize ("-O2")

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

const int N = 1000000 + 10;
const ll MOD = 1000000000 + 7;
const ll INF = 1000000010;
const ll LOG = 25;
const ll K = 100000000;

map<vector<int>, int> mp;
vector<vector<int>> V;
int dis[1300][1300], q, pnt, mn[1300][1300], mark[N];
ll num[N];
int P[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
vector<int> vv, D[N], G[N];

void BT(int x = 0, ll n = 1, int mx = 41){
	if (x == 10){
		vector<int> KK = vv;
		reverse(all(KK));
		mp[KK] = ++pnt;
		V.pb(KK);
		return;
	}
	for (int i = 0; i <= mx && n < K; i++){
		vv.pb(i);
		BT(x + 1, n, i);
		vv.pop_back();
		n *= P[x];
	}
}

void BFS(int v){
	dis[v][v] = 0;
	//cout << v << endl;
	queue<int> Q;
	Q.push(v);

	while (Q.size()){
		//cout << "YES2" << endl;
		int fr = Q.front();
		mn[v][num[fr]] = min(mn[v][num[fr]], dis[v][fr]);
		Q.pop();
		for (auto u:G[fr]){
			if (dis[v][u] > dis[v][fr] + 1){
				dis[v][u] = dis[v][fr] + 1;
				Q.push(u);
			}
		}
	}
}

int32_t main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> q;
	BT();
//	cout << pnt<< endl;
	mark[1] = 1;
	for (int i = 1; i < N; i++){
		if (!mark[i]){
			for (int j = i; j < N; j += i){
				mark[j] = 1;
				int x = j;
				int cnt = 0;
				while (x % i == 0){
					x /= i;
					cnt++;
				}
				D[j].pb(cnt);
			}
		}
		while (D[i].size() < 10) D[i].pb(0);
		sort(all(D[i]));
	}
	vector<int> adad;
	for (vector<int> u:V){
		for (int i = 0; i < 10; i++){
			vector<int> uu;
			for (auto x:u) uu.pb(x);
			uu[i] --;
			sort(all(uu));
			if (mp.count(uu)) G[mp[uu]].pb(mp[u]), G[mp[u]].pb(mp[uu]);
			uu.clear();
			for (auto x:u) uu.pb(x);
			uu[i] ++;
			sort(all(uu));
			if (mp.count(uu)) G[mp[uu]].pb(mp[u]), G[mp[u]].pb(mp[uu]);;
		}
		ll res = 1;
		for (auto x:u) res *= x + 1;
		num[mp[u]] = res;
		adad.pb(res);
	}
	sort(all(adad));
	adad.resize(unique(all(adad)) - adad.begin());
	for (int i = 1; i <= pnt; i++){
		num[i] = lower_bound(all(adad), num[i]) - adad.begin() + 1;
	}
	//cout << pnt << endl;
//	cout << "YES" << endl;
	memset(mn, 31, sizeof mn);
	memset(dis, 31, sizeof dis);
	for (int i = 1; i <= pnt; i++) BFS(i);
	//cout << dis[mp[D[9]]][mp[D[3]]] << '\n';
	for (int i = 1; i <= q; i++){
		int a, b;
		cin >> a >> b;
		if (!mp.count(D[a]) || !mp.count(D[b])) assert(0);
		a = mp[D[a]];
		b = mp[D[b]];
		int ans = 10000;
		for (int j = 1; j <= pnt; j++){
			ans = min(ans, mn[a][j] + mn[b][j]);
		}
		cout << ans << '\n';
	}

	return 0;
}


#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define mp make_pair
#define pu push
#define po pop
#define N 100005
#define FAST ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);srand(time(NULL));
using namespace std;
ll n1,n2,x,y,i=0,j;
string a,b,ans;
bool flag=0;
int main(void){
	cin>>a>>b;
	sort(a.begin(),a.end());

	n1=a.length();
	n2=b.length();

	if(n2>n1)return reverse(a.begin(),a.end()),cout<<a,0;

	for(i=0;i<n1;i++){
		for(j=i+1;j<n1;j++){
			string t=a;
			swap(t[i],t[j]);
			if(stoll(t)>=stoll(a) && stoll(t)<=stoll(b))
			a=t;
		}
	}
	cout<<a;
	return 0;
}


// tarptaeya
#include <bits/stdc++.h>
// base types
#define _i int
#define _l long
#define _ll long long
#define _f float
#define _d double
#define _ld long double
// containters
#define _str std::string
#define _v std::vector
#define _vi std::vector<int>
#define _vl std::vector<long>
#define _vll std::vector<long long>
#define _vstr std::vector<std::string>
#define _vvi std::vector<std::vector<int> >
#define _psb push_back
#define _ppb pop_back
#define _s std::set
#define _si std::set<int>
#define _sl std::set<long>
#define _sll std::set<long long>
#define _sstr std::set<std::string>
#define _ins insert
#define _rem remove
#define _p std::pair
#define _m std::map
#define _q std::queue
#define _ps push
#define _pp pop
// algorithms
#define _sort(a) std::sort(a.begin(), a.end())
// io
#define _fio std::ios_base::sync_with_stdio(0); std::cin.tie(0)
#define _in std::cin
#define _ina(a, n) for (decltype(n) i = 0; i <  (n); i++) { std::cin >> a[i]; }
#define _out std::cout
#define _outa(a) for (auto i : a) std::cout << i << ' '; std::cout << std::endl;
#define _nl std::endl
// general
#define _rep(i, a, b) for (decltype(b) (i) = (a); i < (b); i++)
#define _till while
#define _max(a, b) (a) > (b) ? (a) : (b)
#define _min(a, b) (a) < (b) ? (a) : (b)
#define _for(i,a) for (auto i : a)
#define _ord(a) a - '0'
#define _mod 1000000007
// https://stackoverflow.com/a/47434423
#define _inf (unsigned)!((int)0)
#define _pi 3.141592653589
#define _eps 0.000000001

int main()
{
    _d n, R, r;
    _in >> n >> R >> r;
    if (R == r || r / (R - r) > 1) {
        if (n == 1 && (R - r < _eps || R > r)) {
            _out << "YES" << _nl;
        } else {
            _out << "NO" << _nl;
        }
    } else {
        _d t = asin(r / (R - r));
        //_out << _pi / t - n << _nl;
        if (_pi / t > n || (_pi / t > n ? _pi / t - n : n - _pi / t) < _eps) {
            _out << "YES" << _nl;
        } else {
            _out << "NO" << _nl;
        }
    }
}


#include <bits/stdc++.h>
using namespace std;

int pot2[20];

int main() {
	pot2[0]=1;
	for (int i=1;i<20;i++){
		pot2[i]=2*pot2[i-1];
	}
	int n,l,r,max_sum=0,min_sum=0;
	cin>>n>>l>>r;
	for(int i=0;i<r;i++){
		if(i<l) min_sum+=pot2[i];
		max_sum+=pot2[i];
	}
	min_sum+=n-l;
	max_sum+=pot2[r-1]*(n-r);
	cout<<min_sum<<" "<<max_sum;
	return 0;
}


#include<bits/stdc++.h>
#define pa pair<int,int>
typedef unsigned long long ull;
typedef long long ll;
using namespace std;
const int N=1e7+10;
int inf=1e9;
const int mod =998244353;
inline int qpow(int a,int b,int Mod){
	int ans=1;
	while(b){
		if(b&1) ans=(1ll*ans*a%Mod);
		b>>=1;a=1ll*a*a%Mod;
	}
	return ans;
}

inline int rd(){
	int x=0;int f=1;char s=getchar();
	while(!isdigit(s)){ if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){ x=(x<<1)+(x<<3)+s-'0';s=getchar(); }
	return f==1?x:-x;
}
int cas;
ll n,x,y,k,M;
ll dp[720721][18];
ll a[N];
ll fac[20];
int main(){

	cin>>n>>a[1]>>x>>y>>k>>M;
	for(int i=2;i<=n;i++) a[i]=(x*a[i-1]+y)%M;
//	for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;

	fac[0]=1;int lcm=1;
	for(int i=1;i<k;i++){
		fac[i]=fac[i-1]*n%mod;
		lcm=1ll*lcm*i/__gcd(i,lcm);
	}
//	cout<<lcm<<endl;
	ll ans=0;
	memset(dp,0,sizeof dp);
	for(int i=1;i<=n;i++) {
		ans=(ans+lcm*(a[i]/lcm)%mod*k%mod*fac[k-1]%mod)%mod;
		a[i]%=lcm;
		dp[a[i]][0]++;
	}
//	cout<<ans<<endl;
	for(int j=0;j<k;j++){
		for(int i=0;i<lcm;i++){
			dp[i][j+1]=(dp[i][j+1] + (n-1)*dp[i][j]%mod)%mod;
			dp[i-(i%(j+1))][j+1]=(dp[i-(i%(j+1))][j+1] + dp[i][j])%mod;
		}
	}

	for(int j=0;j<k;j++){
		for(int i=0;i<lcm;i++){
			ans=(ans+i*dp[i][j]%mod*fac[k-j-1]%mod)%mod;
		}
	}
	cout<<ans<<endl;

	return 0;
}


#include <iostream>

using namespace std;

int main()
{
    int k;
    while(cin>>k)
    {
        k+=k;
        int a[10]={};
        int flag=1;
        for(int i=0;i<16;i++)
        {
            char ch;
            cin>>ch;
            if(ch>='0'&&ch<='9')
            {
                a[ch-'0']++;
                if(a[ch-'0']>k) flag=0;
            }
        }
        if(flag==1) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=100005;
int INF=0x3f3f3f3f;
LL mod=1e9+7;
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    string s[13]={
        "",
        "x^y^z",
        "x^z^y",
        "(x^y)^z",
        "(x^z)^y",
        "y^x^z",
        "y^z^x",
        "(y^x)^z",
        "(y^z)^x",
        "z^x^y",
        "z^y^x",
        "(z^x)^y",
        "(z^y)^x",
    };
    int ans=1;
    long double x,y,z;
    long double mx=-10000,t;
    cin>>x>>y>>z;
    if(x<=1&&y<=1&&z<=1){
        ans=1;
        mx=pow(x,pow(y,z));
        t=pow(x,pow(z,y));
        if(t>mx){
            mx=t;
            ans=2;
        }
        t=pow(pow(x,y),z);
        if(t>mx){
            mx=t;
            ans=3;
        }
        t=pow(y,pow(x,z));
        if(t>mx){
            mx=t;
            ans=5;
        }
       t=pow(y,pow(z,x));
        if(t>mx){
            mx=t;
            ans=6;
        }
        t=pow(pow(y,x),z);
        if(t>mx){
            mx=t;
            ans=7;
        }
        t=pow(z,pow(x,y));
        if(t>mx){
            mx=t;
            ans=9;
        }
        t=pow(z,pow(y,x));
        if(t>mx){
            mx=t;
            ans=10;
        }
        t=pow(pow(z,x),y);
        if(t>mx){
            mx=t;
            ans=11;
        }
    }
    else{
        //cout<<"go"<<endl;
        if(x>1){
            t=z*log(y)+log(log(x));
            if(t>mx){
                mx=t;
                ans=1;
            }
            t=y*log(z)+log(log(x));
            if(t>mx){
                mx=t;
                ans=2;
            }
            t=log(y)+log(z)+log(log(x));
            if(t>mx){
                mx=t;
                ans=3;
            }
        }
        if(y>1){
            t=z*log(x)+log(log(y));
            if(t>mx){
                mx=t;
                ans=5;
            }
            t=x*log(z)+log(log(y));
            if(t>mx){
                mx=t;
                ans=6;
            }
            t=log(x)+log(z)+log(log(y));
            if(t>mx){
                mx=t;
                ans=7;
            }
        }
        if(z>1){
            t=y*log(x)+log(log(z));
            if(t>mx){
                mx=t;
                ans=9;
            }
            t=x*log(y)+log(log(z));
            if(t>mx){
                mx=t;
                ans=10;
            }
            t=log(x)+log(y)+log(log(z));
            if(t>mx){
                mx=t;
                ans=11;
            }
        }
    }

    cout<<s[ans]<<endl;
    return 0;
}


#include <algorithm>
#include <iostream>
#include <string>
#include <stack>

int main()
{
	int n, x, y, t, a = 0, b = 0;
	std::cin >> n;
	t = std::sqrt(double(n));
	for (y = 1; y <= t; ++y)
	{
		x = n / y;
		if (x*y == n)
		{
			a = y;
			b = x;
		}
	}
	std::cout << a << ' ' << b;
	return 0;
}