#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<cmath>
#include<cassert>
#include<map>
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define MAX_V 500
using namespace std;
typedef pair<int,int> ii;

// library start
struct edge
{
  int to,cap,cost,rev;
  edge(int to=-inf,int cap=-inf,int cost=-inf,int rev=-inf):to(to),cap(cap),cost(cost),rev(rev){}
};
int V;
vector<edge> G[MAX_V];
int dist[MAX_V];
int prevv[MAX_V],preve[MAX_V];

void add_edge(int from,int to,int cap,int cost)
{
  G[from].push_back(edge(to,cap,cost,G[to].size()));
  G[to].push_back(edge(from,0,-cost,G[from].size()-1));
}

int min_cost_flow(int s,int t,int f)
{
  int res = 0;
  while(f > 0)
    {
      rep(i,MAX_V)dist[i] = inf;
      dist[s] = 0;
      bool update = true;
      while(update)
	{
	  update = false;
	  rep(v,V)
	    {
	      if(dist[v] == inf)continue;
	      rep(i,G[v].size())
		{
		  edge &e = G[v][i];
		  if(e.cap > 0 && dist[e.to] > dist[v] + e.cost)
		    {
		      dist[e.to] = dist[v] + e.cost;
		      prevv[e.to] = v;
		      preve[e.to] = i;
		      update = true;
		    }
		}
	    }
	}

      if(dist[t] == inf)break;

      int 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;
}
// library end

int n;
short W[MAX_V][MAX_V];
short E[MAX_V][MAX_V];
char  F[MAX_V][MAX_V];

int main()
{
  while(cin >> n)
    {
      rep(i,n)rep(j,n)cin >> W[i][j];
      rep(i,n)rep(j,n)cin >> E[i][j];
      int cost = 0;
      rep(i,n)rep(j,n)
	{
	  cin >> F[i][j];
	  if(F[i][j] == 'o')cost += E[i][j];
	}

      V = n*2 + 3;
      int source = 2*n+1,sink = 2*n+2;
      const int diff = 10000;

      rep(y,n)add_edge(source,y,1,0);

      rep(y,n)
	{
	  rep(x,n)
	    {
	      add_edge(y,n+x,1,(F[y][x]=='o'?-E[y][x]+diff:W[y][x]+diff));
	    }
	}

      rep(x,n)add_edge(n+x,sink,1,0);

      /*
      rep(i,V)
	{
	  cout << "from " << i << endl;
	  rep(j,G[i].size())
	    {
	      edge e = G[i][j];
	      cout << e.to << "," << e.cost << "," << e.cap << endl;
	    }
	  cout << endl;
	}
      */
      cost += min_cost_flow(source,sink,inf)-n*diff;

      cout << cost << endl;
      int cnt = 0;
      map<ii,bool> found;
      rep(y,n)
	{
	  for(int x=0;x<G[y].size();x++)
	    {
	      if(G[y][x].cap == 0 && G[y][x].to != source && G[y][x].to != sink)
		{
		  //cout << "(" << y << "," << G[y][x].to << ")" << endl;
		  if(F[y][G[y][x].to-n] == '.')
		    {
		      cnt++;
		    }
		  else
		    {
		      found[ii(G[y][x].to-n,y)] = true;
		    }
		  break;
		}
	    }
	}


      rep(y,n)rep(x,n)if(!found[ii(x,y)] && F[y][x] == 'o')cnt++;

      cout << cnt << endl;

      rep(y,n)
	{
	  for(int x=0;x<G[y].size();x++)
	    {
	      if(G[y][x].cap == 0 && G[y][x].to != source && G[y][x].to != sink)
		{
		  if(F[y][G[y][x].to-n] == '.')
		    {
		      cout << y+1 << " " << G[y][x].to-n+1 << " write" << endl;
		    }
		  break;
		}
	    }
	}


      rep(y,n)rep(x,n)if(!found[ii(x,y)] && F[y][x] == 'o')
	{
	  cout << y+1 << " " << x+1 << " erase" << endl;
	}


    }
  return 0;
}

Measured memory_bytes: 2324