#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

#define all(c) (c).begin(), (c).end()
#define loop(i,a,b) for(int i=a; i<int(b); i++)
#define rep(i,b) loop(i,0,b)
#define iter(it,c) for(auto it=c.begin(); it!=c.end(); ++it)

int const inf = 1<<28;

typedef int Weight;
struct Edge {
    int src, dst;
    Weight cap, cost;
    int rev; bool is_rev;
    Edge(int src, int dst, Weight cap, Weight cost, int rev, bool is_rev=false) :
        src(src), dst(dst), cap(cap), cost(cost), rev(rev), is_rev(is_rev) {}
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

typedef vector<Weight> Array;
typedef vector<Array> Matrix;

void add_edge(Graph & g, int src, int dst, int cap, int cost) {
    g[src].emplace_back(src, dst, cap, cost, g[dst].size(), false);
    g[dst].emplace_back(dst, src, 0, -cost, g[src].size() - 1, true); // rev
}

struct State {
    int v,dist;
    State(int v, int dist)
        :v(v), dist(dist) {}
    bool operator<(State const & s)const{
        return dist>s.dist;
    }
};

// s 縺九ｉ t 縺ク縺ョ豬・? f 縺ョ譛&#128;蟆剰イサ逕ィ豬√ｒ豎ゅａ繧・// 豬√○縺ェ縺・&#63728;エ蜷医・ -1 繧定ソ斐☆
int primal_dual(Graph & g, int s, int t, Weight f) {
    int n=g.size();
    Array h(n), pv(n), pe(n);
    Weight res = 0;
    while (f > 0) {
        priority_queue<State> q;
        Array dist(n,inf);
        dist[s] = 0;
        q.push(State(s, 0));
        while (q.size()) {
            State p = q.top(); q.pop();
            int v = p.v;
            if (dist[v] < p.dist) continue;
            iter(e,g[v]){
                if (e->cap > 0 && dist[e->dst] > dist[v] + e->cost + h[v] - h[e->dst]) {
                    dist[e->dst] = dist[v] + e->cost + h[v] - h[e->dst];
                    pv[e->dst] = v;
                    pe[e->dst] = e-g[v].begin();
                    q.push(State(e->dst, dist[e->dst]));
                }
            }
        }
        if (dist[t] == inf) {
            return -1;
        }
        rep(v,n) h[v]+=dist[v];
        int d = f;
        for (int v = t; v != s; v = pv[v]) {
            d = min(d, g[pv[v]][pe[v]].cap);
        }
        f -= d;
        res += d * h[t];
        for (int v = t; v != s; v = pv[v]) {
            Edge &e = g[pv[v]][pe[v]];
            e.cap -= d;
            g[v][e.rev].cap += d;
        }
    }
    return res;
}

int n;
Weight W[128][128], E[128][128];
char f[128][128];

void solve(){
    Weight C=0;
    rep(i,n)rep(j,n){
        if(f[i][j]=='o')C+=E[i][j];
    }

    Graph g(n*2+2);
    int s=n*2, t=n*2+1;
    rep(i,n){
        add_edge(g,s,i,1,0);
        add_edge(g,i+n,t,1,0);
    }
    rep(i,n)rep(j,n){
        if(f[i][j]=='o'){
            add_edge(g,i,j+n,1,-E[i][j]);
        }else{
            add_edge(g,i,j+n,1,W[i][j]);
        }
    }

    printf("%d\n",C+primal_dual(g,s,t,n));
    static int ans[10000][3];
    int cnt=0;

    rep(i,g.size()){
        rep(j,g[i].size()){
            auto & e=g[i][j];
            if(e.is_rev || e.cost==0) continue;
            if(f[e.src][e.dst-n]=='o' && e.cap!=0){
                cnt++;
                ans[cnt][0]=e.src+1;
                ans[cnt][1]=e.dst-n+1;
                ans[cnt][2]=0;
            }else if(f[e.src][e.dst-n]=='.' && e.cap==0){
                cnt++;
                ans[cnt][0]=e.src+1;
                ans[cnt][1]=e.dst-n+1;
                ans[cnt][2]=1;
            }
        }
    }
    printf("%d\n",cnt);
    rep(i,cnt){
        printf("%d %d %s\n",ans[i][0],ans[i][1],ans[i][2]==0 ? "erase" : "write");
    }
}

int main(){
    scanf("%d",&n);
    rep(i,n)rep(j,n){
        scanf("%d",&W[i][j]);
    }
    rep(i,n)rep(j,n){
        scanf("%d",&E[i][j]);
    }
    rep(i,n){
        scanf("%s",f[i]);
    }
    solve();
}

Measured memory_bytes: 1896