import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.*;
 
public class dictionary_bgp_wa {
 
    class Edge implements Comparable<Edge> {
        int from, to, w, d;
 
        @Override
        public int compareTo(Edge o) {
            return w - o.w;
        }
    }
 
    public void solve() throws Exception {
        int n = nextInt();
        s = new String[n];
        for (int i = 0; i < n; ++i) {
            s[i] = nextToken();
        }
 
        while (true) {
            boolean one = false;
            for (int i = 0; i < n;) {
                boolean remove = false;
                for (int j = 0; j < n; j++) {
                    if (i == j) {
                        continue;
                    }
                    if (s[j].indexOf(s[i]) != -1) {
                        remove = true;
                    }
                }
                if (remove) {
                    one = true;
                    for (int j = i + 1; j < n; j++) {
                        s[j - 1] = s[j];
                    }
                    n--;
                } else {
                    i++;
                }
            }
            if (!one) break;
        }
 
 
        int[][] w = new int[n][n];
        int[][] shift = new int[n][n];
        Edge[] e = new Edge[n * n];
        int ec = 0;
 
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                w[i][j] = -1;
 
                for (int d = 0; d < s[i].length(); d++) {
                    int common = 0;
                    while (d + common < s[i].length() && common < s[j].length() && s[i].charAt(d + common) == s[j].charAt(common)) {
                        common++;
                    }
                    if (w[i][j] == -1 || s[j].length() - common < w[i][j]) {
                        w[i][j] = s[j].length() - common;
                        shift[i][j] = d;
                    }
                }
 
                if (w[i][j] != -1) {
                    e[ec] = new Edge();
                    e[ec].from = i;
                    e[ec].to = j;
                    e[ec].w = w[i][j];
                    e[ec].d = shift[i][j];
                    ec++;
                }
            }
        }
 
        Arrays.sort(e, 0, ec);
 
 
        int[] p = new int[n];
        boolean[] canIn = new boolean[n];
        int bestSum = Integer.MAX_VALUE;
        int bestRoot = -1;
        int[] bestE = new int[n - 1];
        int[] curE = new int[n - 1];
 
        for (int root = 0; root < n; root++) {
            for (int i = 0; i < n; i++) {
                p[i] = i;
                canIn[i] = true;
            }
            canIn[root] = false;
 
            int sum = s[root].length();
            int curC = 0;
            for (int i = 0; i < ec; i++) {
                Edge cur = e[i];
                if (canIn[cur.to] && getp(p, cur.from) != getp(p, cur.to)) {
                    unite(p, cur.from, cur.to);
                    canIn[cur.to] = false;
                    sum += cur.w;
                    curE[curC++] = i;
                }
            }
 
//            out.println(s[root] + " " + sum);
            if (sum < bestSum) {
                bestSum = sum;
                bestRoot = root;
                System.arraycopy(curE, 0, bestE, 0, n - 1);
            }
        }
 
        outC = 1;
        outP = new int[n * 11];
        outChar = new char[n * 11];
        outP[1] = 0;
 
        int current = 1;
        for (int i = 0; i < s[bestRoot].length(); i++) {
            ++outC;
            outP[outC] = current;
            outChar[outC] = s[bestRoot].charAt(i);
            current = outC;
        }
 
        dfs(e, n, bestRoot, bestE, current);
 
        out.println(outC);
        for (int i = 1; i <= outC; i++) {
            out.print(outP[i]);
            if (outP[i] > 0) {
                out.print(" " + outChar[i]);
            }
            out.println();
        }
    }
 
    int outC;
    int[] outP;
    char[] outChar;
    String[] s;
 
    private void dfs(Edge[] e, int n, int i, int[] taken, int current) {
        for (int index = 0; index < n - 1; index++) {
            Edge cur = e[taken[index]];
            if (cur.from == i) {
                int from2 = s[cur.to].length() - cur.w;
                int point = moveUp(current, s[i].length() - from2 - cur.d);
                int next = addEdge(point, s[cur.to], from2);
 
                dfs(e, n, cur.to, taken, next);
            }
        }
    }
 
    private int addEdge(int point, String s, int from) {
        for (int i = from; i < s.length(); i++) {
            outC++;
            outP[outC] = point;
            outChar[outC] = s.charAt(i);
            point = outC;
        }
        return point;
    }
 
    private int moveUp(int current, int steps) {
        for (int i = 0; i < steps; i++) {
            current = outP[current];
        }
        return current;
    }
 
    Random random = new Random(42);
 
    private void unite(int[] p, int i, int j) {
        i = getp(p, i);
        j = getp(p, j);
        if (random.nextBoolean()) {
            p[i] = j;
        } else {
            p[j] = i;
        }
    }
 
    private int getp(int[] p, int i) {
        return p[i] == i ? i : (p[i] = getp(p, p[i]));
    }
 
 
    int nextInt() {
        return Integer.parseInt(nextToken());
    }
 
    String nextToken() {
        while (st == null || !st.hasMoreTokens()) {
            try {
                st = new StringTokenizer(br.readLine()) ;
            } catch (Exception e) {
                eof = true;
                return "0";
            }
        }
        return st.nextToken();
    }
 
    public static void main(String[] args) {
        new dictionary_bgp_wa().run();
    }
 
    BufferedReader br;
    StringTokenizer st;
    PrintWriter out;
    boolean eof;
 
    public void run() {
        try {
            br = new BufferedReader(new FileReader("dictionary.in"));
            out = new PrintWriter("dictionary.out");
            solve();
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(-1);
        } finally {
            out.close();
        }
    }
 
}