#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <string.h>
#include <cmath>

using namespace std;
typedef long long i64;
typedef long double ld;
typedef pair<i64,i64> P;
#define rep(i,s,e) for(int (i) = (s);(i) <= (e);++(i))

#include <queue>
#include <set>
#include <vector>
using namespace std;
using i64 = long long;

struct Graph {
  struct edge {
    int to;
    i64 cap;
    i64 cost;
    int rev;
  };

  int n;
  vector<vector<edge>> edges;

  Graph(int N) {
    n = N;
    edges.resize(n, vector<edge>());
  }

  int size() const { return n; }

  vector<edge> &operator[](int v) { return edges[v]; }
};

struct Primal_Dual {
  Graph g;
  const int n;
  Primal_Dual(int n_) : g(n_), n(n_) {}

  void add_edge(int from,int to , i64 cost,i64 cap,i64 revcap){
    g[from].push_back({to, cap, cost , (int)g[to].size()});
    g[to].push_back({from, revcap, -cost, (int)g[from].size() - 1});
  }

  i64 minimumCostFlow(int s, int t, i64 f) {
    using Pi = pair<i64, i64>;
    priority_queue<Pi, vector<Pi>, greater<Pi>> que;
    vector<int> prevv(n, -1);
    vector<int> preve(n, -1);
    vector<i64> potential(n, 0);
    i64 res = 0;
    while (f > 0) {
      vector<i64> dist(n, 1e9);
      que.push({0, s});
      dist[s] = 0;
      while (!que.empty()) {
        Pi p = que.top();
        que.pop();
        if (dist[p.second] < p.first)
          continue;
        for (int i = 0; i < (int)g[p.second].size(); i++) {
          auto &e = g[p.second][i];
          i64 next =
              dist[p.second] + e.cost + potential[p.second] - potential[e.to];
          if (e.cap > 0 && dist[e.to] > next) {
            dist[e.to] = next;
            prevv[e.to] = p.second;
            preve[e.to] = i;
            que.push({dist[e.to], e.to});
          }
        }
      }
      if (dist[t] == 1e9)
        return -1;
      for (int v = 0; v < n; v++) {
        potential[v] += dist[v];
      }
      i64 d = f;
      for (int v = t; v != s; v = prevv[v]) {
        d = min(d, g[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d * potential[t];

      for (int v = t; v != s; v = prevv[v]) {
        auto &e = g[prevv[v]][preve[v]];
        e.cap -= d;
        g[v][e.rev].cap += d;
      }
    }
    return res;
  }
};

int n;
int w[101][101];
int e[101][101];

int fie[101][101];

int main(){
    cin >> n;
    rep(i,1,n)rep(j,1,n){
        cin >> w[i][j];
    }
    rep(i,1,n)rep(j,1,n){
        cin >> e[i][j];
    }
    Primal_Dual pd(n * n + 10);
    int sum = 0;
    int s = 0;
    int t = n * n + 9;

    rep(i,1,n){
      pd.add_edge(s,i,0,1,0);
      pd.add_edge(i + n,t,0,1,0);
    }
    rep(i,1,n){
        string s;
        cin >> s;
        rep(j,1,n){
            if(s[j - 1] == '.'){
                pd.add_edge(i,j + n,w[i][j],1,0);
                fie[i][j] = 0;
            }
            else{
                pd.add_edge(i,j + n,-e[i][j],1,0);
                fie[i][j] = 1;
                sum += e[i][j];
            }
        }
    }

    cout << sum + pd.minimumCostFlow(s,t,n) << endl;

    vector<P> write_a ,erase_a;
    rep(i,1,n){
      for(auto & e : pd.g[i]){
        if(e.cap == 0){
          if(fie[i][e.to - n] == 0){
            write_a.push_back({i,e.to - n});
          }
          else{
            fie[i][e.to - n] = 0;
          }
        }
      }
    }

    rep(i,1,n)rep(j,1,n){
      if(fie[i][j] == 1){
        erase_a.push_back({i,j});
      }
    }

    cout << write_a.size() + erase_a.size() << endl;
    for(auto & e : write_a){
      cout << e.first << " " << e.second << " write" << endl;
    }
    for(auto & e : erase_a){
      cout << e.first << " " << e.second << " erase" << endl;
    }
    
}




Measured memory_bytes: 4328