import java.io.File;
import java.io.PrintWriter;
import java.util.*;

public class dictionary_gk {
    public static final int NOT_VISITED = -1;
    public static final char NO_CHAR = (char) -1;

    static Scanner in;
    static PrintWriter out;

    int minId;
    int time;

    Deque<Vertex> stack = new ArrayDeque<>();
    class Vertex {
        List<Edge> edges = new ArrayList<>();
        int enter = NOT_VISITED;
        boolean visiting;
        Vertex representative;

        public int visit() {
            visiting = true;
            enter = time++;
            int ret = enter;
            stack.add(this);
            for (Edge edge : edges) {
                if (edge.weight == 0) {
                    if (edge.to.enter == NOT_VISITED) {
                        ret = Math.min(ret, edge.to.visit());
                    } else if (edge.to.visiting) {
                        ret = Math.min(ret, edge.to.enter);
                    }
                }
            }
            visiting = false;

            if (ret == enter) {
                representative = new Vertex();
                Vertex v;
                do {
                    v = stack.removeLast();
                    v.representative = representative;
                } while (v != this);
            }
            return ret;
        }

        public void build(boolean global, Collection<Edge> used) {
            visiting = true;
            for (Edge edge : edges) {
                if (edge.weight == 0) {
                    if (!edge.to.visiting && (global || edge.to.representative == representative)) {
                        used.add(edge);
                        edge.to.build(global, used);
                    }
                }
            }
        }

        public void dump(int id, Set<Edge> used) {
            for (Edge edge : edges) {
                if (used.contains(edge)) {
                    if (edge.ch != NO_CHAR) {
                        int child = ++minId;
                        dictionary_gk.out.println(id + " " + edge.ch);
                        edge.to.dump(child, used);
                    } else {
                        edge.to.dump(id, used);
                    }
                }
            }
        }
    }

    class Edge {
        Vertex to;
        int weight;
        char ch;
        Edge original;

        Edge(Vertex to, int weight, char ch) {
            this.to = to;
            this.weight = weight;
            this.ch = ch;
        }

        Edge(Vertex to, Edge original) {
            this.to = to;
            this.weight = original.weight;
            this.original = original;
        }
    }

    void run() {
        int n = in.nextInt();
        String[] strings = new String[n];
        for (int i = 0; i < n; i++) {
            strings[i] = in.next();
        }

        for (String string : strings) {
            for (int i = 0; i < string.length() + 1; i++) {
                Vertex p = getVertex(string.substring(0, i));
                if (i != 0) {
                    getVertex(string.substring(0, i - 1)).edges.add(new Edge(p, 1, string.charAt(i - 1)));
                }
                for (int j = 1; j < i; j++) {
                    Vertex v = getVertex(string.substring(j, i));
                    p.edges.add(new Edge(v, 0, NO_CHAR));
                    p = v;
                }
            }
        }

        Set<Edge> edges = chinese(getVertex(""), vertices.values());

        int c = 1;
        for (Edge edge : edges) {
            if (edge.ch != NO_CHAR) {
                c++;
            }
        }


        out.println(c);
        out.println(0);
        getVertex("").dump(++minId, edges);
    }

    Set<Edge> chinese(Vertex root, Collection<Vertex> vertices) {
        Map<Vertex, Integer> minWeights = new HashMap<>();
        for (Vertex vertex : vertices) for (Edge edge : vertex.edges) {
            Integer minWeight = minWeights.get(edge.to);
            minWeights.put(edge.to, minWeight == null ? edge.weight : Math.min(minWeight, edge.weight));
        }
        for (Vertex vertex : vertices) for (Edge edge : vertex.edges) {
            edge.weight -= minWeights.get(edge.to);
        }

        root.visit();
        boolean all = true;
        for (Vertex vertex : vertices) {
            if (vertex.enter == NOT_VISITED) {
                vertex.visit();
                all = false;
            }
        }

        Set<Edge> used = new HashSet<>();
        if (all) {
            root.build(true, used);
            return used;
        }

        Set<Vertex> condensation = new HashSet<>();
        for (Vertex vertex : vertices) {
            condensation.add(vertex.representative);
        }

        for (Vertex vertex : vertices) for (Edge edge : vertex.edges) {
            if (vertex.representative != edge.to.representative) {
                vertex.representative.edges.add(new Edge(edge.to.representative, edge));
            }
        }

        root.build(false, used);
        for (Edge edge : chinese(root.representative, condensation)) {
            used.add(edge.original);
            edge.original.to.build(false, used);
        }
        return used;
    }

    Map<String, Vertex> vertices = new HashMap<>();
    Vertex getVertex(String s) {
        Vertex vertex = vertices.get(s);
        if (vertex == null) {
            vertex = new Vertex();
            vertices.put(s, vertex);
        }
        return vertex;
    }

    public static void main(String[] args) throws Exception {
        in = new Scanner(new File("dictionary.in"));
        out = new PrintWriter("dictionary.out");

        new dictionary_gk().run();

        in.close();
        out.close();
    }
}
