#include <bits/stdc++.h>
using namespace std;

using weight = int;
using P = std::pair<int, int>;
using pii = pair<int, int>;

constexpr weight INF = 1e9;

struct edge {
    int to, cap;
    weight cost;
    int rev;
};

using edges = std::vector<edge>;
using graph = std::vector<edges>;

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

// verified
weight min_cost_flow(graph& g, int s, int t, weight f) {
    weight res = 0;
    std::vector<weight> h(g.size(), 0);
    std::vector<weight> dist(g.size());
    std::vector<int> prevv(g.size()), preve(g.size());
    std::fill(h.begin(), h.end(), 0);
    while(f > 0) {
        std::priority_queue<P, std::vector<P>, std::greater<P>> que;
        std::fill(dist.begin(), dist.end(), INF);
        dist[s] = 0;
        que.push(P{0, s});
        while(!que.empty()) {
            P p = que.top(); que.pop();
            int v = p.second;
            if(dist[v] < p.first) {
                continue;
            }
            for(int i=0; i<g[v].size(); ++i) {
                edge& e = g[v][i];
                if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    que.push(P{dist[e.to], e.to});
                }
            }
        }
        if(dist[t] == INF) {
            return -1;
        }
        for(int v=0; v<g.size(); ++v) {
            h[v] += dist[v];
        }

        weight d = f;
        for(int v=t; v!=s; v=prevv[v]) {
            d = min(d, g[prevv[v]][preve[v]].cap);
        }
        f -= d;
        res += d * h[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 main() {
    int n;
    cin >> n;
    vector<vector<int>> W(n, vector<int>(n));
    vector<vector<int>> E(n, vector<int>(n));
    vector<string> F(n);
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cin >> W[i][j];
        }
    }
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            cin >> E[i][j];
        }
    }
    for(int i = 0; i < n; ++i) {
        cin >> F[i];
    }

    graph g(n + n + 2);
    int const source = n + n;
    int const sink = n + n + 1;
    int min_cost = 0;
    for(int i = 0; i < n; ++i) {
        for(int j = 0; j < n; ++j) {
            int cost = 0;
            if(F[i][j] == 'o') {
                min_cost += E[i][j];
                cost -= E[i][j];
            } else {
                cost += W[i][j];
            }
            add_edge(g, i, j + n, 1, cost);
        }
    }
    for(int i = 0; i < n; ++i) {
        add_edge(g, source, i, 1, 0);
        add_edge(g, i + n, sink, 1, 0);
    }

    min_cost += min_cost_flow(g, source, sink, n);

    vector<pii> erased;
    vector<pii> wrote;
    for(int i = 0; i < n; ++i) {
        for(auto& e : g[i]) {
            if(e.cap == 0) {
                if(F[i][e.to - n] == '.') {
                    wrote.emplace_back(i + 1, e.to - n + 1);
                }
            } else {
                if(F[i][e.to - n] == 'o') {
                    erased.emplace_back(i + 1, e.to - n + 1);
                }
            }
        }
    }

    cout << min_cost << endl;
    cout << erased.size() + wrote.size() << endl;
    for(auto& p : erased) {
        cout << p.first << ' ' << p.second << " erase" << endl;
    }
    for(auto& p : wrote) {
        cout << p.first << ' ' << p.second << " write" << endl;
    }
}


Measured memory_bytes: 3416