#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const long long INF = 1e16;
int N, M;
vector<vector<long long>> W, V;
vector<vector<int>> P, Q;
// Hàm tính tổng giá trị của một hàng ô vuông dựa trên mask
long long get_row_cost(int r, int mask, int m_faces) {
long long cost = 0;
for (int j = 0; j < m_faces; ++j) {
if ((mask >> j) & 1) {
// Giá trị của ô vuông (r, j+1)
cost += W[r][j + 1] - W[r][j + 2] + V[r][j + 1] - V[r + 1][j + 1];
}
}
return cost;
}
// Kiểm tra mask có thỏa mãn ràng buộc dọc P trong hàng r không
bool is_valid_mask(int r, int mask, int m_faces) {
// Xét các đường dọc p[r][j]
for (int j = 1; j <= m_faces + 1; ++j) {
if (P[r][j] == 0) {
int left_bit = (j == 1) ? 0 : ((mask >> (j - 2)) & 1);
int right_bit = (j == m_faces + 1) ? 0 : ((mask >> (j - 1)) & 1);
if (left_bit != right_bit) return false;
}
}
return true;
}
// Kiểm tra hai mask liên tiếp có thỏa mãn ràng buộc ngang Q không
bool is_compatible(int r, int old_mask, int new_mask, int m_faces) {
// q[r][j] nối ô vuông hàng r-1 và hàng r tại cột j
for (int j = 1; j <= m_faces; ++j) {
if (Q[r][j] == 0) {
int top_bit = (old_mask >> (j - 1)) & 1;
int bot_bit = (new_mask >> (j - 1)) & 1;
if (top_bit != bot_bit) return false;
}
}
return true;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
int n_in, m_in;
cin >> n_in >> m_in;
// Đọc dữ liệu thô
vector<vector<long long>> w_raw(n_in, vector<long long>(m_in + 1));
for (int i = 1; i < n_in; ++i) for (int j = 1; j <= m_in; ++j) cin >> w_raw[i][j];
vector<vector<long long>> v_raw(n_in + 1, vector<long long>(m_in));
for (int i = 1; i <= n_in; ++i) for (int j = 1; j < m_in; ++j) cin >> v_raw[i][j];
vector<string> p_raw(n_in), q_raw(n_in + 1);
for (int i = 1; i < n_in; ++i) cin >> p_raw[i];
for (int i = 1; i <= n_in; ++i) cin >> q_raw[i];
// Quyết định xoay lưới để min(N, M) là chiều cột (M)
bool swapped = false;
if (n_in < m_in) {
swapped = true;
N = m_in; M = n_in;
W.assign(N + 1, vector<long long>(M + 1, 0));
V.assign(N + 1, vector<long long>(M + 1, 0));
P.assign(N + 1, vector<int>(M + 1, 1));
Q.assign(N + 1, vector<int>(M + 1, 1));
for(int i=1; i<n_in; ++i) for(int j=1; j<=m_in; ++j) {
V[j][i] = w_raw[i][j];
Q[j][i] = p_raw[i][j-1] - '0';
}
for(int i=1; i<=n_in; ++i) for(int j=1; j<m_in; ++j) {
W[j][i] = v_raw[i][j];
P[j][i] = q_raw[i][j-1] - '0';
}
} else {
N = n_in; M = m_in;
W = w_raw; V = v_raw;
P.assign(N, vector<int>(M + 1));
Q.assign(N + 1, vector<int>(M));
for(int i=1; i<N; ++i) for(int j=1; j<=M; ++j) P[i][j] = p_raw[i][j-1] - '0';
for(int i=1; i<=N; ++i) for(int j=1; j<M; ++j) Q[i][j] = q_raw[i][j-1] - '0';
}
int m_faces = M - 1;
int n_faces = N - 1;
if (m_faces <= 0) { cout << 0 << endl; return 0; }
vector<long long> dp(1 << m_faces, -INF);
dp[0] = 0; // Trạng thái bắt đầu (màu trắng hết)
for (int i = 1; i <= n_faces; ++i) {
vector<long long> next_dp(1 << m_faces, -INF);
long long row_costs[1 << 10];
bool valid_masks[1 << 10];
for (int mask = 0; mask < (1 << m_faces); ++mask) {
row_costs[mask] = get_row_cost(i, mask, m_faces);
valid_masks[mask] = is_valid_mask(i, mask, m_faces);
}
for (int mask = 0; mask < (1 << m_faces); ++mask) {
if (!valid_masks[mask]) continue;
for (int prev_mask = 0; prev_mask < (1 << m_faces); ++prev_mask) {
if (dp[prev_mask] == -INF) continue;
if (is_compatible(i, prev_mask, mask, m_faces)) {
next_dp[mask] = max(next_dp[mask], dp[prev_mask] + row_costs[mask]);
}
}
}
dp = next_dp;
}
// Ràng buộc cuối cùng với biên dưới (hàng N)
long long max_aesthetic = -INF;
for (int mask = 0; mask < (1 << m_faces); ++mask) {
if (dp[mask] == -INF) continue;
bool ok = true;
for (int j = 1; j <= m_faces; ++j) {
if (Q[N][j] == 0 && ((mask >> (j - 1)) & 1) != 0) ok = false;
}
if (ok) max_aesthetic = max(max_aesthetic, dp[mask]);
}
if (max_aesthetic < 0) cout << 0 << endl; // Luôn có cách xây rỗng = 0
else cout << max_aesthetic << endl;
return 0;
}