#include <iostream>
#include <vector>
#include <cassert>
#include <queue>
#include <limits>
#include <set>

using namespace std;
using ll = long long;
template <typename T>
constexpr T INF = numeric_limits<T>::max() / 10;

class CostFlow
{
public:
    using Cost = ll;
    using Ind = int;
    using Capacity = ll;
    using T = ll;

    struct Edge {
        Edge(const Ind from_, const Ind to_, const Ind reverse_, const Capacity capacity_, const Cost cost_, bool is_reverse_ = false) : from{from_}, to{to_}, reverse{reverse_}, capacity{capacity_}, flow{0}, cost{cost_}, is_reverse{is_reverse_} {}
        Ind from;
        Ind to;
        Ind reverse;
        Capacity capacity;
        Capacity flow;
        Cost cost;
        bool is_reverse;
    };

    CostFlow(const Ind v) : V{v}
    {
        edge.resize(v);
        m_dist.resize(v);
        m_potential.resize(v);
        m_prev_v.resize(v);
        m_prev_e.resize(v);
    }

    void addEdge(const Ind from, const Ind to, const Capacity capacity, const Cost cost)
    {
        edge[from].push_back(Edge{from, to, (Ind)edge[to].size(), (Capacity)capacity, (Cost)cost, false});
        edge[to].push_back(Edge{to, from, (Ind)(edge[from].size() - 1), (Capacity)0, (Cost)(-cost), true});
    }

    T minCostFlow(const Ind s, const Ind t, T f)
    {
        using P = pair<Cost, Ind>;
        T res = 0;
        fill(m_potential.begin(), m_potential.end(), 0);

        // Bellman-Ford(Replace this when DAG)
        for (int i = 0; i < V; i++) {
            m_potential[i] = INF<T>;
        }
        m_potential[s] = 0;
        bool no_negative_loop = true;
        for (int i = 0; i < V; i++) {
            for (int v = 0; v < V; v++) {
                if (m_potential[v] != INF<T>) {
                    for (const auto& e : edge[v]) {
                        if (e.capacity <= 0) {
                            continue;
                        }
                        if (m_potential[e.to] > m_potential[v] + e.cost) {
                            m_potential[e.to] = m_potential[v] + e.cost;
                            if (i == V - 1) {
                                m_potential[e.to] = -INF<T>;  // Confirm " -INF < min(possible_cost) * V "
                                no_negative_loop = false;
                            }
                        }
                    }
                }
            }
        }
        if (not no_negative_loop) {
            // ????????¨?????????
        }
        ////show(m_potential)

        while (f > 0) {
            // Dijkstra
            priority_queue<P, vector<P>, greater<P>> q;
            fill(m_dist.begin(), m_dist.end(), INF<T>);
            m_dist[s] = 0;
            q.push(make_pair(0, s));
            while (not q.empty()) {
                const P p = q.top();
                q.pop();
                const Ind v = p.second;
                if (m_dist[v] < p.first) {
                    continue;
                }
                for (Ind i = 0; i < edge[v].size(); i++) {
                    const auto& e = edge[v][i];
                    if (e.capacity > e.flow and m_dist[e.to] > m_dist[v] + e.cost + m_potential[v] - m_potential[e.to]) {
                        m_dist[e.to] = m_dist[v] + e.cost + m_potential[v] - m_potential[e.to];
                        m_prev_v[e.to] = v;
                        m_prev_e[e.to] = i;
                        q.push(make_pair(m_dist[e.to], e.to));
                    }
                }
            }
            if (m_dist[t] == INF<T>) {
                //                return -1;
                return res;
            }
            for (Ind v = 0; v < V; v++) {
                m_potential[v] += m_dist[v];
            }

            T d = f;
            for (Ind v = t; v != s; v = m_prev_v[v]) {
                const auto& e = edge[m_prev_v[v]][m_prev_e[v]];
                d = min(d, (T)(e.capacity - e.flow));
            }
            f -= d;
            res += d * m_potential[t];
            for (Ind v = t; v != s; v = m_prev_v[v]) {
                auto& e = edge[m_prev_v[v]][m_prev_e[v]];
                e.flow += d;
                edge[v][e.reverse].flow -= d;
            }
        }
        return res;
    }

    const Ind V;
    vector<vector<Edge>> edge;

private:
    vector<Cost> m_dist;
    vector<Cost> m_potential;
    vector<Ind> m_prev_v;
    vector<Ind> m_prev_e;
};

struct Ope {
    bool o;
    int r;
    int c;
};

int main()
{
    int n;
    cin >> n;
    vector<vector<ll>> W(n, vector<ll>(n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> W[i][j];
        }
    }
    vector<vector<ll>> E(n, vector<ll>(n));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> E[i][j];
        }
    }

    vector<vector<bool>> use(n, vector<bool>(n, false));
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        for (int j = 0; j < n; j++) {
            use[i][j] = (s[j] == 'o');
        }
    }

    ll sum = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            sum += (use[i][j] ? E[i][j] : 0);
        }
    }

    CostFlow flow(2 * n + 2);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            flow.addEdge(i, j + n, 1, (use[i][j] ? -E[i][j] : W[i][j]));
        }
    }
    const int s = 2 * n;
    const int t = 2 * n + 1;
    for (int i = 0; i < n; i++) {
        flow.addEdge(s, i, 1, 0);
        flow.addEdge(n + i, t, 1, 0);
    }
    cout << sum + flow.minCostFlow(s, t, n) << endl;

    vector<Ope> op;
    for (int i = 0; i < n; i++) {
        for (const auto& e : flow.edge[i]) {
            if (e.is_reverse) {
                continue;
            }
            if (e.flow == 1) {
                if (not use[i][e.to - n]) {
                    op.push_back(Ope{false, i, e.to - n});
                }
            } else {
                if (use[i][e.to - n]) {
                    op.push_back(Ope{true, i, e.to - n});
                }
            }
        }
    }

    cout << op.size() << endl;
    for (const auto& o : op) {
        cout << o.r + 1 << " " << o.c + 1 << " " << (o.o ? "erase" : "write") << endl;
    }

    return 0;
}

Measured memory_bytes: 4520