import java.io.*;
import java.util.*;
 
public class dictionary_keka_wa {
    private static void solve() throws IOException {
        int n = nextInt();
        String[] words = new String[n];
        for (int i = 0; i < n; i++) {
            words[i] = nextToken();
        }
        Arrays.sort(words, new Comparator<String>() {
 
            @Override
            public int compare(String o1, String o2) {
                return o2.length() - o1.length();
            }
        });
        List<String> good = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            boolean ok = true;
            for (int j = 0; j < i; j++) {
                if (words[j].indexOf(words[i]) >= 0) {
                    ok = false;
                }
            }
            if (ok) {
                good.add(words[i]);
            }
        }
        words = good.toArray(new String[good.size()]);
        n = words.length;
        List<Edge> allEdges = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            allEdges.add(new Edge(0, i + 1, 0));
            for (int j = 0; j < n; j++) {
                if (j == i) {
                    continue;
                }
                String w1 = words[j];
                String w2 = words[i];
                int maxPrefix = 0;
                while (maxPrefix + 1 <= w2.length()
                        && w1.indexOf(w2.substring(0, maxPrefix + 1)) >= 0) {
                    ++maxPrefix;
                }
                allEdges.add(new Edge(j + 1, i + 1, -maxPrefix));
            }
        }
        int[] component = new int[n + 1];
        for (int i = 0; i < n + 1; i++) {
            component[i] = i;
        }
 
        List<Edge> answer = bestTree(n + 1, component, allEdges);
 
        List<Integer> edges[] = new List[n + 1];
        for (int i = 0; i < edges.length; i++) {
            edges[i] = new ArrayList<>();
        }
        for (Edge edge : answer) {
            edges[edge.from].add(edge.to);
        }
 
        Queue<Integer> bfs = new ArrayDeque<>();
        bfs.add(0);
 
        List<Integer> parentForNode = new ArrayList<>();
        List<Character> parentLetter = new ArrayList<>();
        int[][] nodesForWord = new int[n + 1][];
        nodesForWord[0] = new int[] { 0 };
        parentForNode.add(-1);
        parentLetter.add(' ');
 
        while (!bfs.isEmpty()) {
            int u = bfs.poll();
            int[] nodes = nodesForWord[u];
            String w1 = u == 0 ? "" : words[u - 1];
            for (int v : edges[u]) {
                if (nodesForWord[v] != null) {
                    continue;
                }
                String w2 = words[v - 1];
                int maxPrefix = 0;
                while (maxPrefix + 1 <= w2.length()
                        && w1.indexOf(w2.substring(0, maxPrefix + 1)) >= 0) {
                    ++maxPrefix;
                }
                int index = w1.indexOf(w2.substring(0, maxPrefix));
                int ok = nodes[index + maxPrefix];
 
                int[] newNodes = new int[w2.length() + 1];
                System.arraycopy(nodes, index, newNodes, 0, maxPrefix + 1);
 
                for (int i = maxPrefix; i < w2.length(); i++) {
                    char letter = w2.charAt(i);
                    parentLetter.add(letter);
                    parentForNode.add(ok);
                    ok = parentForNode.size() - 1;
                    newNodes[i + 1] = ok;
                }
                nodesForWord[v] = newNodes;
                bfs.add(v);
            }
        }
 
        out.println(parentForNode.size());
        for (int i = 0; i < parentForNode.size(); i++) {
            if (i == 0) {
                out.println(0);
            } else {
                out.println((parentForNode.get(i) + 1) + " "
                        + parentLetter.get(i));
            }
        }
 
    }
 
    private static List<Edge> bestTree(int components, int[] component,
            List<Edge> allEdges) {
 
        int[] minIn = new int[components];
        Arrays.fill(minIn, Integer.MAX_VALUE);
        for (Edge edge : allEdges) {
            int c1 = component[edge.from];
            int c2 = component[edge.to];
            if (c1 == c2) {
                continue;
            }
            if (edge.weight < minIn[c2]) {
                minIn[c2] = edge.weight;
            }
        }
 
        for (Edge edge : allEdges) {
            int c1 = component[edge.from];
            int c2 = component[edge.to];
            if (c1 == c2) {
                continue;
            }
            edge.weight -= minIn[c2];
        }
        if (components == 2) {
            List<Edge> result = new ArrayList<>();
            for (Edge edge : allEdges) {
                int c1 = component[edge.from];
                int c2 = component[edge.to];
                if (c1 == c2) {
                    continue;
                }
                if (edge.weight == 0) {
                    result.add(edge);
                    break;
                }
            }
            return result;
        }
 
        SCCfinder ok = new SCCfinder(components);
        for (Edge edge : allEdges) {
            int c1 = component[edge.from];
            int c2 = component[edge.to];
            if (c1 == c2) {
                continue;
            }
            if (edge.weight == 0) {
                ok.addEdge(c1, c2);
            }
        }
 
        int[] comp = ok.findComponents();
        int[] newComponent = component.clone();
        int n = component.length;
        for (int i = 0; i < n; i++) {
            newComponent[i] = comp[component[i]];
        }
        int newComponents = ok.components;
 
        List<Edge> thing = bestTree(newComponents, newComponent, allEdges);
 
        boolean[] hasIn = new boolean[n];
 
        for (Edge edge : thing) {
            hasIn[edge.to] = true;
        }
 
        for (Edge edge : allEdges) {
            int c1 = component[edge.from];
            int c2 = component[edge.to];
            if (c1 == c2) {
                continue;
            }
            if (edge.weight == 0 && newComponent[c1] == newComponent[c2]
                    && !hasIn[edge.to]) {
                thing.add(edge);
            }
        }
 
        return thing;
    }
 
    static class SCCfinder {
        int n;
        int[] component;
        boolean[] visited;
        List<Integer>[] edgesOut;
        List<Integer>[] edgesIn;
 
        SCCfinder(int n) {
            this.n = n;
            component = new int[n];
            visited = new boolean[n];
            edgesOut = new List[n];
            edgesIn = new List[n];
            for (int i = 0; i < n; i++) {
                edgesOut[i] = new ArrayList<>();
                edgesIn[i] = new ArrayList<>();
            }
            dfsOrder = new int[n];
        }
 
        void addEdge(int u, int v) {
            edgesOut[u].add(v);
            edgesIn[v].add(u);
        }
 
        int[] findComponents() {
            dfsTime = 0;
            Arrays.fill(visited, false);
            for (int i = 0; i < n; i++) {
                dfs1(i);
            }
            Arrays.fill(component, -1);
            components = 0;
            for (int i = n - 1; i >= 0; --i) {
                int u = dfsOrder[i];
                if (component[u] >= 0) {
                    continue;
                }
                component[u] = components++;
                dfs2(u);
            }
            return component;
        }
 
        int dfsTime = 0;
        int[] dfsOrder;
        int components;
 
        void dfs1(int u) {
            if (visited[u]) {
                return;
            }
            visited[u] = true;
            for (int v : edgesOut[u]) {
                dfs1(v);
            }
            dfsOrder[dfsTime++] = u;
        }
 
        void dfs2(int u) {
            for (int v : edgesIn[u]) {
                if (component[v] < 0) {
                    component[v] = component[u];
                    dfs2(v);
                }
            }
        }
    }
 
    static class Edge {
        int from, to, weight;
 
        public Edge(int from, int to, int weight) {
            this.from = from;
            this.to = to;
            this.weight = weight;
        }
    }
 
    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new FileReader("dictionary.in"));
        out = new PrintWriter("dictionary.out");
        solve();
        out.close();
    }
 
    static BufferedReader br;
    static PrintWriter out;
    static StringTokenizer st;
 
    static String nextToken() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            String line = br.readLine();
            if (line == null) {
                return null;
            }
            st = new StringTokenizer(line);
        }
        return st.nextToken();
    }
 
    static int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }
 
    static long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }
}