#include <bits/stdc++.h>
using namespace std;
#define FOR(i,k,n) for(int i = (int)(k); i < (int)(n); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) a.begin(), a.end()
#define MS(m,v) memset(m,v,sizeof(m))
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
const int MOD = 1000000007;
const int INF = MOD + 1;
const ld EPS = 1e-12;
template<class T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<class T> T &chmax(T &a, const T &b) { return a = max(a, b); }

/*--------------------template--------------------*/

typedef int Weight;
typedef int Flow;
struct Edge {
	int src, dest, rev;
	Flow cap;
	Weight cost;
	bool operator < (const Edge &rhs) const
	{
		return cost > rhs.cost;
	}
	Edge(int s, int d) : src(s), dest(d) { ; }
	Edge(int s, int d, int c) : src(s), dest(d), cost(c) { ; }
	Edge(int s, int d, int r, Flow cp, Weight cst) : src(s), dest(d), rev(r), cap(cp), cost(cst) { ; }
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void add_edge(Graph &g, int from, int to, Flow cap, Weight cost)
{
	g[from].push_back(Edge(from, to, (int)g[to].size(), cap, cost));
	g[to].push_back(Edge(to, from, (int)g[from].size() - 1, 0, -cost));
}

Weight mincost_flow(Graph &g, int s, int t, Flow f)
{
	const int n = g.size();
	Weight res = 0;
	Array dist(n);
	vi prevv(n), preve(n);
	while (f > 0)
	{
		REP(i, n) dist[i] = (i == s) ? 0 : INF;
		bool update = true;
		while (update)
		{
			update = false;
			for (int v = 0; v < n; v++)
			{
				if (dist[v] == INF) continue;
				REP(i, g[v].size())
				{
					Edge& e = g[v][i];
					if (e.cap > 0 && dist[e.dest] > dist[v] + e.cost)
					{
						dist[e.dest] = dist[v] + e.cost;
						prevv[e.dest] = v;
						preve[e.dest] = i;
						update = true;
					}
				}
			}
		}
		if (dist[t] == INF) return -1; // cannot flow
		Flow d = f;
		for (int v = t; v != s; v = prevv[v])
		{
			d = min(d, g[prevv[v]][preve[v]].cap);
		}
		f -= d;
		res += d * dist[t];
		for (int v = t; v != s; v = prevv[v])
		{
			Edge &e = g[prevv[v]][preve[v]];
			e.cap -= d;
			g[v][e.rev].cap += d;
		}
	}
	return res;
}

int N;
vector<vi> W, E;
vs f;

int main()
{
	cin.sync_with_stdio(false); cout << fixed << setprecision(10);
	cin >> N;
	W.resize(N, vi(N));
	E.resize(N, vi(N));
	f.resize(N);
	REP(i, N)REP(j, N) cin >> W[i][j];
	REP(i, N)REP(j, N) cin >> E[i][j];
	REP(i, N) cin >> f[i];
	Graph g(N * 2 + 2);
	int src = N * 2, sink = N * 2 + 1;
	REP(i, N)
	{
		add_edge(g, src, i, 1, 0);
		add_edge(g, N + i, sink, 1, 0);
	}
	REP(i, N)REP(j, N)
	{
		int cost = 0;
		REP(k, N)
		{
			if (k == j && f[i][k] == '.') cost += W[i][k];
			if (k != j && f[i][k] == 'o') cost += E[i][k];
		}
		add_edge(g, i, N + j, 1, cost);
	}
	cout << mincost_flow(g, src, sink, N) << endl;
	vs res(N, string(N, '.'));
	REP(i, N)
	{
		REP(j, g[i].size())
		{
			if (g[i][j].dest != src && g[i][j].cap == 0)
			{
				res[i][g[i][j].dest - N] = 'o';
			}
		}
	}
	vector<tuple<int, int, int>> ans;
	REP(i, N)REP(j, N)
	{
		if (f[i][j] == '.' && res[i][j] == 'o') ans.emplace_back(0, i, j);
		if (f[i][j] == 'o' && res[i][j] == '.') ans.emplace_back(1, i, j);
	}
	cout << ans.size() << endl;
	for (auto t : ans)
	{
		int a, i, j;
		tie(a, i, j) = t;
		if (a == 0) cout << i + 1 << " " << j + 1 << " write" << endl;
		if (a == 1) cout << i + 1 << " " << j + 1 << " erase" << endl;
	}
	return 0;
}

Measured memory_bytes: 3660