#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string>
#include <sstream>
using namespace std;
 
const int INF = (1<<28);
 
class Edge
{
public:
    int src,dst,cst,cap,rev;
    Edge(int src, int dst, int cst, int cap, int rev)
        :src(src),dst(dst),cst(cst),cap(cap),rev(rev)
    {}
};
 
typedef vector<vector<Edge> > Graph;
 
void addEdge(int u, int v, int cap, int cost, Graph& graph)
{
    graph[u].push_back(Edge(u, v, cost, cap, graph[v].size()));
    graph[v].push_back(Edge(v, u, -cost, 0, graph[u].size()-1));
}
 
pair<int, int> minimumCostFlow(int S, int T, int L, Graph& graph)
{
  int V = graph.size();
  vector<int> dist(V), prevv(V), preve(V);
 
  int res = 0, fw = 0;
  while(1) {
    fill(dist.begin(), dist.end(), INF);
    dist[S] = 0;
    bool update = true;
 
    while(update) {
      update = false;
      for(int v = 0; v < V; v++) {
        if(dist[v] == INF) continue;
 
        for(int i=0; i<graph[v].size(); i++) {
          Edge& e = graph[v][i];
          int cost = e.cst;
          if(graph[e.dst][e.rev].cap != 0) cost = 0;
 
          if(e.cap > 0 && dist[e.dst] > dist[e.src] + cost) {
            dist[e.dst] = dist[e.src] + cost;
            prevv[e.dst] = e.src;
            preve[e.dst] = i;
            update = true;
          }
        }
      }
    }
 
    if(dist[T] == INF) break;
 
    int f = INF;
    for(int v = T; v != S; v = prevv[v])
      f = min(f, graph[prevv[v]][preve[v]].cap);
 
    res += dist[T];
    fw += f;
 
    for(int v = T; v != S; v = prevv[v]) {
      Edge& e = graph[prevv[v]][preve[v]];
      e.cap -= f;
      graph[v][e.rev].cap += f;
    }
 
    if(fw >= L) break;
  }
 
  return make_pair(res, fw);
}
 
int ecst[100][100], icst[100][100];
int main()
{
    int N;
    cin >> N;
    for(int i=0; i<N; i++)
    for(int j=0; j<N; j++)
        cin >> icst[i][j];
 
    for(int i=0; i<N; i++)
    for(int j=0; j<N; j++)
        cin >> ecst[i][j];
 
    string field[100];
    for(int i=0; i<N; i++)
        cin >> field[i];
 
    Graph graph(N*2+2);
    for(int i=0; i<N; i++) {
        addEdge(N*2, i, 1, 0, graph);
        addEdge(N+i, N*2+1, 1, 0, graph);
    }
 
    for(int i=0; i<N; i++) 
	for(int j=0; j<N; j++) {
		int cst = 0;
		for(int k=0; k<N; k++) {
			if(field[k][j] == 'o') cst += ecst[k][j];
			if(field[i][k] == 'o') cst += ecst[i][k];
		}

		if(field[i][j] == 'o') cst -= 2*ecst[i][j];
		if(field[i][j] == '.') cst += 2*icst[i][j];
 
        addEdge(j, i+N, 1, cst, graph);
    }
 
    pair<int, int> fw = minimumCostFlow(N*2, N*2+1, N, graph);
 

    cout << fw.first/2 << endl;
 
    int c = 0;
    stringstream ss;
    for(int i=0; i<N; i++) {
        for(int j=0; j<graph[i].size(); j++) {
            Edge& e = graph[i][j];
 
            if(e.dst < N || e.dst >= N*2) continue;
 
            if(field[e.dst-N][e.src] == 'o' && e.cap == 1) {
                c++;
                ss << e.dst + 1 - N << " " << e.src + 1 << " erase" << endl;
            }
            if(field[e.dst-N][e.src] == '.' && e.cap == 0) {
                c++;
                ss << e.dst + 1 - N << " " << e.src + 1 << " write" << endl;
            }
        }
    }
 
    cout << c << endl;
    cout << ss.str();

	//system("pause");
}

Measured memory_bytes: 1840