#include using namespace std; using ll = long long; using ld = long double; using pll = pair; #define rep(i,n) for (int i = 0; i < (n); i++) #define rep1(i,n) for (int i = 1; i <= (n); i++) #define all(a) begin(a), end(a) // aよりもbが大きいならばaをbで更新する // (更新されたならばtrueを返す) template bool chmax(T &a, const T& b) { if (a < b) { a = b; // aをbで更新 return true; } return false; } // aよりもbが小さいならばaをbで更新する // (更新されたならばtrueを返す) template bool chmin(T &a, const T& b) { if (a > b) { a = b; // aをbで更新 return true; } return false; } ll modpow(ll a, ll b, ll m) { ll p = a; ll ans = 1; rep(i,32) { if ((b & (0x01 << i)) != 0) { ans *= p; ans %= m; } p *= p; p %= m; } return (ans); } ll pow(ll a, ll b) { ll p = a; ll ans = 1; rep(i,32) { if ((b & (0x01 << i)) != 0) { ans *= p; } p *= p; } return (ans); } ll Division(ll a, ll b, ll m) { return ((a * modpow(b, m - 2, m)) % m); } struct V { int x, y; V(int x=0, int y=0): x(x), y(y) {} V operator-(const V &a) const { return V(x-a.x, y-a.y); } int cross(const V &a) const { return x*a.y - y*a.x; } int ccw(const V &a) const { int area = cross(a); if (area > 0) return +1; // ccw if (area < 0) return -1; // cw return 0; // collinear } }; /* 2147483648 int max 1000000000 1e9 9223372036854775807 ll max 1000000000000000000 1e18 */ int main() { int N; cin >> N; ll K; cin >> K; vector s(2*N); rep(i,2*N) cin >> s[i]; ll white = 0, black = 0; rep(i,2*N)rep(j,2*N) { if (s[i][j] == '#') black++; else white++; } vector> c(2*N); vector ar; rep(i,2*N)rep(j,2*N) { ll a; cin >> a; c[i].push_back(a); ar.push_back(a); } bool isable = false; if (black%2==0 && white%2==0) isable = true; ll ans = 0; sort(all(ar), greater()); rep(i,black) ans += ar[i]; if (!isable) { cout << ans << endl; return 0; } // シンメトリーの最大 vector dp(black/2+1, (1LL << 63)); dp[0] = 0; rep(i,2*N) { rep(j,N) { rep1(k,black/2) { dp[k] = max(dp[k], dp[k-1]+(c[i][j]+c[i][2*N-1-j])); } } } ans = max(ans, dp[black/2]+K); cout << ans << endl; return 0; }