#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <sstream>
#include <typeinfo>
#include <queue>
#include <stack>
#include <tuple>

using namespace std;


typedef long long ll;
const int MAX_V = 210;
const int INT_INF = 1<<30;
typedef pair<int, int> P;
typedef tuple<int, int, int> T;
struct edge {
	int cap, cost;
};
int V;

edge G[MAX_V][MAX_V];
int h[MAX_V], dist[MAX_V];
int prevv[MAX_V];
bool used[MAX_V];

void add_edge(int from, int to, int cap, int cost) {
	G[from][to] = (edge){cap, cost};
	G[to][from] = (edge){0, -cost};
}

int bit_matching_cost(int s, int t, int f) {
	int res = 0;
	fill_n(h, V, 0);
	while (f > 0) {
		fill_n(dist, V, INT_INF);
		dist[s] = 0;

        fill_n(used, V, false);
        while (true) {
            int v = -1;
            for (int i = 0; i < V; i++) {
                if (!used[i] && (v == -1 || dist[i] < dist[v])){
                    v = i;
                }
            }
            if (v == -1) break;
            used[v] = true;

			for (int i = 0; i < V; i++) {
				edge &e = G[v][i];
				if (e.cap > 0 && dist[i] > dist[v] + e.cost + h[v] - h[i]) {
					dist[i] = dist[v] + e.cost + h[v] - h[i];
					prevv[i] = v;
				}
			}
        }
        /*
		priority_queue<P, vector<P>, greater<P>> que;
		que.push(P(0, s));
		while (!que.empty()) {
			P p = que.top(); que.pop();
			int v = p.second;
			if (dist[v] < p.first) continue;
			for (int i = 0; i < V; i++) {
				edge &e = G[v][i];
				if (e.cap > 0 && dist[i] > dist[v] + e.cost + h[v] - h[i]) {
					dist[i] = dist[v] + e.cost + h[v] - h[i];
					prevv[i] = v;
					que.push(P(dist[i], i));
				}
			}
		}*/
		if (dist[t] == INT_INF) {
			return -1;
		}
		for (int v = 0; v < V; v++) {
			h[v] += dist[v];
		}
		int d = f;
		for (int v = 0; v != s; v = prevv[v]) {
			d = min(d, G[prevv[v]][v].cap);
		}
		f -= d;
		res += d * h[t];
		for (int v = t; v != s; v = prevv[v]) {
			edge &e = G[prevv[v]][v];
			e.cap -= d;
			G[v][prevv[v]].cap += d;
		}
	}
	return res;
}
int cost[MAX_V][MAX_V];


const int MAX_N = 105;
int N;
int W[MAX_N][MAX_N], E[MAX_N][MAX_N];
bool F[MAX_N][MAX_N], F2[MAX_N][MAX_N];

int main(int argc, char *argv[]) {
	cin >> N;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			scanf("%d", &(W[i][j]));
		}
	}
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			scanf("%d", &(E[i][j]));
		}
	}
	int min_f = 0, f = 0;
	for (int i = 0; i < N; i++) {
		string s;
		cin >> s;
		for (int j = 0; j < N; j++) {
			F[i][j] = (s[j] == 'o');
			if (F[i][j]) {
				min_f = min(min_f, -E[i][j]);
				f += E[i][j];
			}
		}
	}
	min_f *= -1;
	V = (N+1)*2;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (F[i][j]) {
				add_edge(i, N+j, 1, -E[i][j]+min_f);
			} else {
				add_edge(i, N+j, 1, W[i][j]+min_f);
			}
		}
	}
	for (int i = 0; i < N; i++) {
		add_edge(N*2, i, 1, 0);
	}
	for (int i = 0; i < N; i++) {
		add_edge(N+i, N*2+1, 1, 0);
	}
	f += bit_matching_cost(N*2, N*2+1, N);
	f -= min_f*N;
	int c = 0;
	vector<T> q;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (F[i][j] == G[i][N+j].cap) {
				c++;
				q.push_back(T(i, j, F[i][j]));
			}
		}
	}
	printf("%d\n%d\n", f, c);
	for (T t: q) {
		printf("%d %d %s\n", get<0>(t)+1, get<1>(t)+1, get<2>(t) ? "erase" : "write");
	} 
    return 0;
}

Measured memory_bytes: 1768