import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class Main {

	public static void main(String[] args) {
		Task mSol = new Task();
		mSol.solve();
		mSol.flush();
		mSol.close();
	}

}

class Task {

	public FasterScanner mFScanner;
	public PrintWriter mOut;

	public Task() {
		mFScanner = new FasterScanner();
		mOut = new PrintWriter(System.out);
	}

	public void solve() {

		int i;
		int firstN, secondN;
		long firstD[];
		long secondD[];
		long commonD[];
		long firstP;
		long secondP;
		long maxDiff = -1;
		long maxA;
		long B;

		firstN = mFScanner.nextInt();
		firstD = new long[firstN];

		for (i = 0; i < firstN; i++)
			firstD[i] = mFScanner.nextLong();

		secondN = mFScanner.nextInt();
		secondD = new long[secondN];

		for (i = 0; i < secondN; i++)
			secondD[i] = mFScanner.nextLong();

		commonD = new long[firstN + secondN];

		Arrays.sort(firstD);
		Arrays.sort(secondD);

		for (i = 0; i < firstN; i++) {
			commonD[i] = firstD[i];
		}
		for (int j = 0; j < secondN; j++) {
			commonD[i + j] = secondD[j];
		}

		Arrays.sort(commonD);

		int index;
		long val;
		int j;
		int n;

		firstP = 3 * firstN;
		secondP = 3 * secondN;

		maxDiff = firstP - secondP;
		maxA = firstP;
		B = secondP;

		n = firstN + secondN;

		for (i = 0; i < n + 2; i++) {

			if (i == n) {
				val = commonD[0] - 1;
			} else if (i == n + 1) {
				val = commonD[n - 1] + 1;
			} else {
				val = commonD[i];
			}
			index = binarySearch(secondD, val);
			j = binarySearch(firstD, val);

			firstP = 3 * (firstN - j) + 2 * j;
			secondP = 3 * (secondN - index) + 2 * index;

			long diff = firstP - secondP;

			if (diff > maxDiff) {
				maxDiff = diff;
				maxA = firstP;
				B = secondP;
			} else if (diff == maxDiff && firstP > maxA) {
				maxA = firstP;
				B = secondP;
			}
		}

		firstP = 2 * firstN;
		secondP = 2 * secondN;

		long diff = firstP - secondP;

		if (diff > maxDiff) {
			maxDiff = diff;
			maxA = firstP;
			B = secondP;
		} else if (diff == maxDiff && firstP > maxA) {
			maxA = firstP;
			B = secondP;
		}

		mOut.println(maxA + ":" + B);

	}

	public int binarySearch(long array[], long val) {

		int count, step, it;
		int first;

		count = array.length;
		first = 0;

		while (count > 0) {
			it = first;
			step = count / 2;
			it += step;

			if (!(val < array[it])) {
				first = ++it;
				count -= step + 1;
			} else {
				count = step;
			}
		}

		return first;

	}

	public void flush() {
		mOut.flush();
	}

	public void close() {
		mOut.close();
	}
}

class FasterScanner {
	private InputStream mIs;
	private byte[] buf = new byte[1024];
	private int curChar;
	private int numChars;

	public FasterScanner() {
		this(System.in);
	}

	public FasterScanner(InputStream is) {
		mIs = is;
	}

	public int read() {
		if (numChars == -1)
			throw new InputMismatchException();
		if (curChar >= numChars) {
			curChar = 0;
			try {
				numChars = mIs.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (numChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public String nextString() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isSpaceChar(c));
		return res.toString();
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	public boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}

}


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class Main {

	public static void main(String[] args) {
		Task mSol = new Task();
		mSol.solve();
		mSol.flush();
		mSol.close();
	}

}

class Task {

	public FasterScanner mFScanner;
	public PrintWriter mOut;

	public Task() {
		mFScanner = new FasterScanner();
		mOut = new PrintWriter(System.out);
	}

	public void solve() {

		int i;
		int firstN, secondN;
		long firstD[];
		long secondD[];
		long firstP;
		long secondP;
		long maxDiff = -1;
		long maxA;
		long B;

		firstN = mFScanner.nextInt();
		firstD = new long[firstN];

		for (i = 0; i < firstN; i++)
			firstD[i] = mFScanner.nextLong();

		secondN = mFScanner.nextInt();
		secondD = new long[secondN];
		for (i = 0; i < secondN; i++)
			secondD[i] = mFScanner.nextLong();

		Arrays.sort(firstD);
		Arrays.sort(secondD);

		int index;
		long val;
		int j;

		firstP = 3 * firstN;
		secondP = 3 * secondN;

		maxDiff = firstP - secondP;
		maxA = firstP;
		B = secondP;

		for (i = 0; i < firstN + 2; i++) {

			if (i == firstN) {
				val = firstD[0] - 1;
			} else if (i == firstN + 1) {
				val = firstD[firstN - 1] + 1;
			} else {
				val = firstD[i];
			}
			index = binarySearch(secondD, val);
			j = binarySearch(firstD, val);

			firstP = 3 * (firstN - j) + 2 * j;
			secondP = 3 * (secondN - index) + 2 * index;

			long diff = firstP - secondP;

			if (diff > maxDiff) {
				maxDiff = diff;
				maxA = firstP;
				B = secondP;
			} else if (diff == maxDiff && firstP > maxA) {
				maxA = firstP;
				B = secondP;
			}
		}

		firstP = 2 * firstN;
		secondP = 2 * secondN;

		long diff = firstP - secondP;

		if (diff > maxDiff) {
			maxDiff = diff;
			maxA = firstP;
			B = secondP;
		} else if (diff == maxDiff && firstP > maxA) {
			maxA = firstP;
			B = secondP;
		}

		mOut.println(maxA + ":" + B);

	}

	public int binarySearch(long array[], long val) {

		int count, step, it;
		int first;

		count = array.length;
		first = 0;

		while (count > 0) {
			it = first;
			step = count / 2;
			it += step;

			if (!(val < array[it])) {
				first = ++it;
				count -= step + 1;
			} else {
				count = step;
			}
		}

		return first;

	}

	public void flush() {
		mOut.flush();
	}

	public void close() {
		mOut.close();
	}
}

class FasterScanner {
	private InputStream mIs;
	private byte[] buf = new byte[1024];
	private int curChar;
	private int numChars;

	public FasterScanner() {
		this(System.in);
	}

	public FasterScanner(InputStream is) {
		mIs = is;
	}

	public int read() {
		if (numChars == -1)
			throw new InputMismatchException();
		if (curChar >= numChars) {
			curChar = 0;
			try {
				numChars = mIs.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (numChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public String nextLine() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isEndOfLine(c));
		return res.toString();
	}

	public String nextString() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isSpaceChar(c));
		return res.toString();
	}

	public long nextLong() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		long res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public int nextInt() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public boolean isSpaceChar(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	public boolean isEndOfLine(int c) {
		return c == '\n' || c == '\r' || c == -1;
	}

}


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

public class C {

    static StringTokenizer st;
    static BufferedReader br;
    static PrintWriter pw;
    public static void main(String[] args) throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        int n = nextInt();
        Integer[]A = new Integer[n+1];
        for (int i = 1; i <= n; i++) {
            A[i] = nextInt();
        }
        Arrays.sort(A, 1, n+1);
        int m = nextInt();
        Integer[]B = new Integer[m+1];
        for (int i = 1; i <= m; i++) {
            B[i] = nextInt();
        }
        Arrays.sort(B, 1, m+1);
        int[]a = new int[n+1], b = new int[m+1];
        for (int i = 1; i <= n; i++) {
            a[i] = A[i].intValue();
        }
        for (int i = 1; i <= m; i++) {
            b[i] = B[i].intValue();
        }
        Integer[]C = new Integer[n+m+1];
        int size = 0;
        for (int i = 1; i <= n; i++) {
            C[++size] = a[i];
        }
        for (int i = 1; i <= m; i++) {
            C[++size] = b[i];
        }
        Arrays.sort(C, 1, size+1);
        int ans1 = 3 * n, ans2 = 3 * m;
        int k1 = 0, k2 = 0;
        int[]c = new int[size+1];
        for (int i = 1; i <= size; i++) {
            c[i] = C[i].intValue();
        }
        for (int i = 1; i <= size; i++) {
            while (k1 < n && a[k1+1] <= c[i])
                k1++;
            while (k2 < m && b[k2+1] <= c[i])
                k2++;
            int cur1 = 2*k1+3*(n-k1);
            int cur2 = 2*k2+3*(m-k2);
            if (cur1-cur2 > ans1-ans2 || cur1-cur2==ans1-ans2 && cur1 > ans1) {
                ans1 = cur1;
                ans2 = cur2;
            }
        }
        System.out.println(ans1+":"+ans2);
        pw.close();
    }
    private static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }
    private static long nextLong() throws IOException {
        return Long.parseLong(next());
    }
    private static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
    private static String next() throws IOException {
        while (st==null || !st.hasMoreTokens())
            st = new StringTokenizer(br.readLine());
        return st.nextToken();
    }
}


import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }
}

class TaskC {

    long[] a;
    long[] b;
    long max;
    long firstPoint;
    long secondPoint;

    public void solve(int testNumber, InputReader in, PrintWriter out) {
        int n = in.nextInt();
        a = new long[n];
        for (int i = 0; i < n; ++i) {
            a[i] = in.nextLong();
        }

        int m = in.nextInt();
        b = new long[m];
        for (int i = 0; i < m; ++i) {
            b[i] = in.nextLong();
        }
        max = Long.MIN_VALUE;
        firstPoint = Long.MIN_VALUE;
        secondPoint = Long.MIN_VALUE;
        Arrays.sort(a);
        Arrays.sort(b);
        for (int i = 0; i < a.length; ++i) {
            calPoint(a[i]-1);
            calPoint(a[i]);
            calPoint(a[i]+1);
        }
        for (int i = 0; i < b.length; ++i) {
            calPoint(b[i]-1);
            calPoint(b[i]);
            calPoint(b[i]+1);
        }
        out.println(firstPoint + ":" + secondPoint);
    }

    void calPoint(long d) {
        if(d < 0) return;
        int n1;
        int n2;
        long pointA, pointB;
        long res = 0;
        n1 = lowerBound(a, d);
        n2 = lowerBound(b, d);
        pointA = 2 * n1 + 3 * (a.length - n1);
        pointB = 2 * n2 + 3 * (b.length - n2);
        res = pointA - pointB;
        if (res > max || (res == max && pointA > firstPoint)) {
            firstPoint = pointA;
            secondPoint = pointB;
            max = res;
        }
    }

    int lowerBound(long[] arr, long key) {
        int left = 0, right = arr.length;
        int mid;
        while (left < right) {
            mid = (left + right) >> 1;
            if (arr[mid] < key) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}

class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream), 32768);
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    public long nextLong() {
        return Long.parseLong(next());
    }

}


import java.util.*;
import java.io.*;
import java.math.*;

import static java.lang.Math.*;

public class Solution implements Runnable {

	int getScore(Integer[] a, int d) {
		int l = -1;
		int r = a.length;
		while (r - l > 1) {
			int mid = (r + l) >> 1;
			if (a[mid] <= d) {
				l = mid;
			} else {
				r = mid;
			}
		}
		int total3 = a.length - l - 1;
		return total3 * 3 + (a.length - total3) * 2;
	}

	public void solve() throws Exception {
		int n = sc.nextInt();
		Integer[] a = new Integer[n];
		for (int i = 0; i < n; i++) {
			a[i] = sc.nextInt();
		}
		Arrays.sort(a);
		int m = sc.nextInt();
		Integer[] b = new Integer[m];
		for (int i = 0; i < m; i++) {
			b[i] = sc.nextInt();
		}
		Arrays.sort(b);

		ArrayList<Integer> possible = new ArrayList<>();
		for (int i = 0; i < n; i++) {
			possible.add(a[i] - 1);
			possible.add(a[i] + 1);
			possible.add(a[i]);
		}
		for (int i = 0; i < m; i++) {
			possible.add(b[i] - 1);
			possible.add(b[i] + 1);
			possible.add(b[i]);
		}
		int bestDifference = Integer.MIN_VALUE / 2;
		int bestA = -1;
		int bestB = -1;
		for (int i = 0; i < possible.size(); i++) {
			int d = possible.get(i);
			int scoreA = getScore(a, d);
			int scoreB = getScore(b, d);
			if (scoreA - scoreB > bestDifference || (scoreA - scoreB == bestDifference && scoreA > bestA)) {
				bestDifference = scoreA - scoreB;
				bestA = scoreA;
				bestB = scoreB;
			}
		}
		out.println(bestA + ":" + bestB);
	}

	static Throwable t;

	BufferedReader in;
	FastScanner sc;
	PrintWriter out;

	@Override
	public void run() {
		try {
			//in = new BufferedReader(new FileReader("input.txt"));
			//out = new PrintWriter(new FileWriter("output.txt"));
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			sc = new FastScanner(in);
			solve();
		} catch (Throwable t) {
			Solution.t = t;
		} finally {
			out.close();
		}
	}

	public static void main(String[] args) throws Throwable {
		Thread thread = new Thread(null, new Solution(), "", 1 << 26);
		thread.start();
		thread.join();
		if (Solution.t != null)
			throw t;
	}

}

class FastScanner {

	BufferedReader in;
	StringTokenizer st;

	public FastScanner(BufferedReader in) {
		this.in = in;
	}

	public String nextToken() throws Exception {
		while (st == null || !st.hasMoreTokens())
			st = new StringTokenizer(in.readLine());
		return st.nextToken();
	}

	public int nextInt() throws Exception {
		return Integer.parseInt(nextToken());
	}

	public long nextLong() throws Exception {
		return Long.parseLong(nextToken());
	}

	public double nextDouble() throws Exception {
		return Double.parseDouble(nextToken());
	}

}


import java.util.*;
import java.io.*;
public class C {
    public static PrintStream out = System.out;
    public static InputReader in = new InputReader(System.in);
    public static void main(String args[]) {
        int N = in.nextInt();
        double[] a = new double[N];
        for (int i = 0; i < N; i++) {
            a[i] = in.nextInt();
        }
        int M = in.nextInt();
        double[] b = new double[M];
        for (int i = 0; i < M; i++) {
            b[i] = in.nextInt();
        }
        Arrays.sort(b);
        Arrays.sort(a);
        int valA = -600000;
        int valB = 600000;
        for (int i = 0; i <= a.length; i++) {
            double cut;
            if (i == a.length) {
                cut = a[i - 1] + 0.5;
            } else {
                cut = a[i] - 0.5;
            }
            int bi = Arrays.binarySearch(b, cut);
            bi = -(bi + 1); // bi, bi+1 ... greater or equal of b
            int threeB = M - 1 - bi + 1;
            int twoB = bi - 1 + 1;

            int ai = Arrays.binarySearch(a, cut);
            ai = -(ai + 1);
            int threeA = N - 1 - ai + 1;
            int twoA = ai - 1 + 1;

            int curA = twoA * 2 + threeA * 3;
            int curB = twoB * 2 + threeB * 3;
            int curDiff = curA - curB;
            if (valA - valB < curDiff || (valA - valB == curDiff && valA < curA)) {
                valA = curA;
                valB = curB;
            }
        }
        out.println(valA + ":" + valB);
    }
}
class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;
    public InputReader(InputStream stream) {
	reader = new BufferedReader(new InputStreamReader(stream), 32768);
	tokenizer = null;
    }
    public String next() {
	while (tokenizer == null || !tokenizer.hasMoreTokens()) {
	    try {
		tokenizer = new StringTokenizer(reader.readLine());
	    } catch (IOException e) {
		throw new RuntimeException(e);
	    }
	}
	return tokenizer.nextToken();
    }
    public double nextDouble() {
	return Double.parseDouble(next());
    }
    public long nextLong() {
	return Long.parseLong(next());
    }
    public int nextInt() {
	return Integer.parseInt(next());
    }
}


import java.util.*;
import java.io.*;
public class C {
    public static PrintStream out = System.out;
    public static InputReader in = new InputReader(System.in);
    public static void main(String args[]) {
        int N = in.nextInt();
        double[] a = new double[N];
        for (int i = 0; i < N; i++) {
            a[i] = in.nextInt();
        }
        int M = in.nextInt();
        double[] b = new double[M];
        for (int i = 0; i < M; i++) {
            b[i] = in.nextInt();
        }
        Arrays.sort(b);
        Arrays.sort(a);
        int valA = -600000;
        int valB = 600000;
        for (int i = 0; i <= a.length + 1; i++) {
            double cut;
            if (i == a.length) {
                cut = a[i - 1] + 0.5;
            } else if (i < a.length) {
                cut = a[i] - 0.5;
            } else {
                cut = Double.MAX_VALUE;
            }
            int bi = Arrays.binarySearch(b, cut);
            bi = -(bi + 1); // bi, bi+1 ... greater or equal of b
            int threeB = M - 1 - bi + 1;
            int twoB = bi - 1 + 1;

            int ai = Arrays.binarySearch(a, cut);
            ai = -(ai + 1);
            int threeA = N - 1 - ai + 1;
            int twoA = ai - 1 + 1;

            int curA = twoA * 2 + threeA * 3;
            int curB = twoB * 2 + threeB * 3;
            int curDiff = curA - curB;
            if (valA - valB < curDiff || (valA - valB == curDiff && valA < curA)) {
                valA = curA;
                valB = curB;
            }
        }
        out.println(valA + ":" + valB);
    }
}
class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;
    public InputReader(InputStream stream) {
	reader = new BufferedReader(new InputStreamReader(stream), 32768);
	tokenizer = null;
    }
    public String next() {
	while (tokenizer == null || !tokenizer.hasMoreTokens()) {
	    try {
		tokenizer = new StringTokenizer(reader.readLine());
	    } catch (IOException e) {
		throw new RuntimeException(e);
	    }
	}
	return tokenizer.nextToken();
    }
    public double nextDouble() {
	return Double.parseDouble(next());
    }
    public long nextLong() {
	return Long.parseLong(next());
    }
    public int nextInt() {
	return Integer.parseInt(next());
    }
}


import java.util.*;
import java.io.*;
public class C {
    public static PrintStream out = System.out;
    public static InputReader in = new InputReader(System.in);
    public static void main(String args[]) {
        int N = in.nextInt();
        double[] a = new double[N];
        for (int i = 0; i < N; i++) {
            a[i] = in.nextInt();
        }
        int M = in.nextInt();
        double[] b = new double[M];
        for (int i = 0; i < M; i++) {
            b[i] = in.nextInt();
        }
        Arrays.sort(b);
        Arrays.sort(a);
        int valA = -600000;
        int valB = 600000;
        for (int i = 0; i < a.length; i++) {
            double cut = a[i] - 0.5;
            int bi = Arrays.binarySearch(b, cut);
            bi = -(bi + 1); // bi, bi+1 ... greater or equal of b
            int threeB = M - 1 - bi + 1;
            int twoB = bi - 1 + 1;

            int ai = Arrays.binarySearch(a, cut);
            ai = -(ai + 1);
            int threeA = N - 1 - ai + 1;
            int twoA = ai - 1 + 1;

            int curA = twoA * 2 + threeA * 3;
            int curB = twoB * 2 + threeB * 3;
            int curDiff = curA - curB;
            if (valA - valB < curDiff || (valA - valB == curDiff && valA < curA)) {
                valA = curA;
                valB = curB;
            }
        }
        out.println(valA + ":" + valB);
    }
}
class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;
    public InputReader(InputStream stream) {
	reader = new BufferedReader(new InputStreamReader(stream), 32768);
	tokenizer = null;
    }
    public String next() {
	while (tokenizer == null || !tokenizer.hasMoreTokens()) {
	    try {
		tokenizer = new StringTokenizer(reader.readLine());
	    } catch (IOException e) {
		throw new RuntimeException(e);
	    }
	}
	return tokenizer.nextToken();
    }
    public double nextDouble() {
	return Double.parseDouble(next());
    }
    public long nextLong() {
	return Long.parseLong(next());
    }
    public int nextInt() {
	return Integer.parseInt(next());
    }
}


import java.util.*;
import java.io.*;
public class C {
    public static PrintStream out = System.out;
    public static InputReader in = new InputReader(System.in);
    public static void main(String args[]) {
        int N = in.nextInt();
        double[] a = new double[N];
        for (int i = 0; i < N; i++) {
            a[i] = in.nextInt();
        }
        int M = in.nextInt();
        double[] b = new double[M];
        for (int i = 0; i < M; i++) {
            b[i] = in.nextInt();
        }
        Arrays.sort(b);
        int valA = -600000;
        int valB = 600000;
        for (int i = 0; i < a.length; i++) {
            double cut = a[i] - 0.5;
            int bi = Arrays.binarySearch(b, cut);
            bi = -(bi + 1); // bi, bi+1 ... greater or equal of b
            // while (bi >= 1 && b[bi - 1] >= b) bi--; // double check
            int threeB = M - 1 - bi + 1;
            int twoB = bi - 1 + 1;
            int ai = Arrays.binarySearch(a, cut);
            ai = -(ai + 1);
            int threeA = N - 1 - ai + 1;
            int twoA = ai - 1 + 1;
            int curA = twoA * 2 + threeA * 3;
            int curB = twoB * 2 + threeB * 3;
            int curDiff = curA - curB;
            if (valA - valB < curDiff || (valA - valB == curDiff && valA < curA)) {
                valA = curA;
                valB = curB;
            }
        }
        out.println(valA + ":" + valB);
    }
}
class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;
    public InputReader(InputStream stream) {
	reader = new BufferedReader(new InputStreamReader(stream), 32768);
	tokenizer = null;
    }
    public String next() {
	while (tokenizer == null || !tokenizer.hasMoreTokens()) {
	    try {
		tokenizer = new StringTokenizer(reader.readLine());
	    } catch (IOException e) {
		throw new RuntimeException(e);
	    }
	}
	return tokenizer.nextToken();
    }
    public double nextDouble() {
	return Double.parseDouble(next());
    }
    public long nextLong() {
	return Long.parseLong(next());
    }
    public int nextInt() {
	return Integer.parseInt(next());
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;

public class Main
{
    private static MyScanner sc;
    private static PrintWriter out;
    public static void main(String[] args)
    {
    	sc = new MyScanner();
    	out = new PrintWriter(System.out);
    	int n = sc.nextInt();
    	int[] arr = new int[n];
    	for(int i = 0; i < n; i++)
    		arr[i] = sc.nextInt();
    	int m = sc.nextInt();
    	int[] brr = new int[m];
    	for(int i = 0; i < m; i++)
    		brr[i] = sc.nextInt();
    	Arrays.sort(arr);
    	Arrays.sort(brr);
    	int i = 0;
    	int j = 0;
    	long aScore = 3 * n;
    	long bScore = 3 * m;

    	if(arr[i] < brr[j]) i++;
    	else if(arr[i] > brr[i]) j++;
    	else
    	{
    		i++;
    		j++;
    	}
    	while(i < arr.length && j < brr.length)
    	{
    		if(arr[i] < brr[j])
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			i++;
    		}
    		else if(arr[i] > brr[j])
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			j++;

    		}
    		else
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			i++;
    			j++;

    		}

    	}

    	long tmpAScore1 = 2 * n;
		long tmpBScore1 = 2 * m;

		long diff1 = tmpAScore1 - tmpBScore1;
		if(diff1 > (aScore - bScore))
		{
			aScore = tmpAScore1;
			bScore = tmpBScore1;
		}

		else if(diff1 == (aScore - bScore) && tmpAScore1 > aScore)
		{
			aScore = tmpAScore1;
			bScore = tmpBScore1;

		}

    	if(i >= arr.length && j >= brr.length)
    	{
    		out.println(aScore + ":" + bScore);
    	}
    	else if(i < arr.length)
    	{
    		out.println("idhar");

    		long tmpAScore = (2 * (i)) + (3 * (n - (i)));
			long tmpBScore = (2 * m);

			long diff = tmpAScore - tmpBScore;
			if(diff > (aScore - bScore))
			{
				aScore = tmpAScore;
				bScore = tmpBScore;
			}

			else if(diff == (aScore - bScore) && tmpAScore > aScore)
			{
				aScore = tmpAScore;
				bScore = tmpBScore;

			}

    		out.println(aScore + ":" + bScore);

    	}

    	else
    	{

    		long tmpAScore = 2 * n;
    		long tmpBScore = (2 * j) + (3 * (m - j));
			long diff = tmpAScore - tmpBScore;
			if(diff > (aScore - bScore))
			{
				aScore = tmpAScore;
				bScore = tmpBScore;
			}

			else if(diff == (aScore - bScore) && tmpAScore > aScore)
			{
				aScore = tmpAScore;
				bScore = tmpBScore;

			}

    		out.println(aScore + ":" + bScore);

    	}

    	out.close();
    }

    private static int max(int a, int b)
    {
        if(a > b) return a;
        else return b;
    }

    private static int min(int a, int b)
    {
        if(a < b) return a;
        else return b;

    }

 private static int abs(int a, int b)
    {
        return (int) Math.abs(a - b);
    }

     public static int modexp(int a, int b, int n)
     {
        if (b == 0) return 1;
        long t = modexp(a, b/2, n);
        long c = (t * t) % n;
        if (b % 2 == 1)
           c = (c * a) % n;
        return (int) c;
    }

 public static class MyScanner
    {
      BufferedReader br;
      StringTokenizer st;

      public MyScanner()
      {
         br = new BufferedReader(new InputStreamReader(System.in));
      }

      String next()
      {
          while (st == null || !st.hasMoreElements())
          {
              try
              {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e)
              {
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      int nextInt()
      {
          return Integer.parseInt(next());
      }

      long nextLong()
      {
          return Long.parseLong(next());
      }

      double nextDouble()
      {
          return Double.parseDouble(next());
      }

      String nextLine()
      {
          String str = "";
	  try
          {
	     str = br.readLine();
	  } catch (IOException e)
          {
	     e.printStackTrace();
	  }
	  return str;
      }

   }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 *
 * @author Aditya Joshi
 * SPOJ / CodeChef / Codeforces / HackerRank / Timus / UVA
 */
public class Main
{
    private static MyScanner sc;
    private static PrintWriter out;
    private static int[] a;
    private static int[] b;

    public static void main(String[] args)
    {
        sc = new MyScanner();
        out = new PrintWriter(System.out);
        int n = sc.nextInt();
        int[] a = new int[n];
        for(int i = 0; i < n; i++) a[i] = sc.nextInt();
        int m = sc.nextInt();
        int[] b = new int[m];
        for(int i = 0; i < m; i++) b[i] = sc.nextInt();

        Arrays.sort(a);
        Arrays.sort(b);
        long ans_a = 0;
        long ans_b = 0;
        for(int i = 0; i < n; i++)
        {
            int cons = a[i];
            long curr_a = (2 * i) + (3 * (n - i));

            int index_b = binarySearch(b, cons);
            long curr_b = 0;
            if(index_b == -1) curr_b = 2 * m;
            else curr_b = (2 * index_b) + (3 * (m - index_b));

            if(curr_a - curr_b > (ans_a - ans_b))
            {
                ans_a = curr_a;
                ans_b = curr_b;
            }

        }
        out.println(ans_a + ":" + ans_b);

        out.close();
    }

   public static int binarySearch(int[] a, int key) {
    int low=0,high=a.length-1;
    while (low<=high) {
        if(low + 1 == high)
        {
             if(key == a[high]) return high;
             else if(key == a[low]) return low;
             else if(key > a[high]) return -1;
             else if(key < a[low]) return 0;
             else return low;

        }

        else if(low == high)
        {
            if(key == a[low]) return low;
            else return -1;
        }
        int mid=(low+high) >>> 1;
        int midVal=a[mid];
        if (midVal < key)
            low=mid+1;
        else if (mid>0 && a[mid-1]>=key) //we already know midval>=key here
            high=mid-1;
        else if (midVal==key) //found the 1st key
             return mid;
        else
            return ~mid;      //found insertion point
    }
    return ~(a.length);       //insertion point after everything
}
    private static int max(int a, int b)
    {
        if(a > b) return a;
        else return b;
    }

    private static int min(int a, int b)
    {
        if(a < b) return a;
        else return b;

    }

    private static int abs(int a, int b)
    {
        return (int) Math.abs(a - b);
    }

     public static int modexp(int a, int b, int n)
     {
        if (b == 0) return 1;
        long t = modexp(a, b/2, n);
        long c = (t * t) % n;
        if (b % 2 == 1)
           c = (c * a) % n;
        return (int) c;
    }

 public static class MyScanner
    {
      BufferedReader br;
      StringTokenizer st;

      public MyScanner()
      {
         br = new BufferedReader(new InputStreamReader(System.in));
      }

      String next()
      {
          while (st == null || !st.hasMoreElements())
          {
              try
              {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e)
              {
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      int nextInt()
      {
          return Integer.parseInt(next());
      }

      long nextLong()
      {
          return Long.parseLong(next());
      }

      double nextDouble()
      {
          return Double.parseDouble(next());
      }

      String nextLine()
      {
          String str = "";
	  try
          {
	     str = br.readLine();
	  } catch (IOException e)
          {
	     e.printStackTrace();
	  }
	  return str;
      }

   }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;

public class Main
{
    private static MyScanner sc;
    private static PrintWriter out;
    public static void main(String[] args)
    {
    	sc = new MyScanner();
    	out = new PrintWriter(System.out);
    	int n = sc.nextInt();
    	int[] arr = new int[n];
    	for(int i = 0; i < n; i++)
    		arr[i] = sc.nextInt();
    	int m = sc.nextInt();
    	int[] brr = new int[m];
    	for(int i = 0; i < m; i++)
    		brr[i] = sc.nextInt();
    	Arrays.sort(arr);
    	Arrays.sort(brr);
    	int i = 0;
    	int j = 0;
    	long aScore = 3 * n;
    	long bScore = 3 * m;

    	if(arr[i] < brr[j]) i++;
    	else if(arr[i] > brr[i]) j++;
    	else
    	{
    		i++;
    		j++;
    	}
    	while(i < arr.length && j < brr.length)
    	{
    		if(arr[i] < brr[j])
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			i++;
    		}
    		else if(arr[i] > brr[j])
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			j++;

    		}
    		else
    		{
    			long tmpAScore = (2 * i) + (3 * (n - i));
    			long tmpBScore = (2 * j) + (3 * (m - j));

    			long diff = tmpAScore - tmpBScore;
    			if(diff > (aScore - bScore))
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;
    			}

    			else if(diff == (aScore - bScore) && tmpAScore > aScore)
    			{
    				aScore = tmpAScore;
    				bScore = tmpBScore;

    			}
    			i++;
    			j++;

    		}

    	}

    	if(i >= arr.length && j >= brr.length)
    	{
    		out.println(aScore + ":" + bScore);
    	}
    	else if(i < arr.length)
    	{

    		long tmpAScore = (2 * (i)) + (3 * (n - (i)));
			long tmpBScore = (2 * m);

			long diff = tmpAScore - tmpBScore;
			if(diff > (aScore - bScore))
			{
				aScore = tmpAScore;
				bScore = tmpBScore;
			}

			else if(diff == (aScore - bScore) && tmpAScore > aScore)
			{
				aScore = tmpAScore;
				bScore = tmpBScore;

			}

    		out.println(aScore + ":" + bScore);

    	}

    	else
    	{
    		long tmpAScore = 2 * n;
    		long tmpBScore = (2 * j) + (3 * (m - j));

			long diff = tmpAScore - tmpBScore;
			if(diff > (aScore - bScore))
			{
				aScore = tmpAScore;
				bScore = tmpBScore;
			}

			else if(diff == (aScore - bScore) && tmpAScore > aScore)
			{
				aScore = tmpAScore;
				bScore = tmpBScore;

			}

    		out.println(aScore + ":" + bScore);

    	}

    	out.close();
    }

    private static int max(int a, int b)
    {
        if(a > b) return a;
        else return b;
    }

    private static int min(int a, int b)
    {
        if(a < b) return a;
        else return b;

    }

 private static int abs(int a, int b)
    {
        return (int) Math.abs(a - b);
    }

     public static int modexp(int a, int b, int n)
     {
        if (b == 0) return 1;
        long t = modexp(a, b/2, n);
        long c = (t * t) % n;
        if (b % 2 == 1)
           c = (c * a) % n;
        return (int) c;
    }

 public static class MyScanner
    {
      BufferedReader br;
      StringTokenizer st;

      public MyScanner()
      {
         br = new BufferedReader(new InputStreamReader(System.in));
      }

      String next()
      {
          while (st == null || !st.hasMoreElements())
          {
              try
              {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e)
              {
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      int nextInt()
      {
          return Integer.parseInt(next());
      }

      long nextLong()
      {
          return Long.parseLong(next());
      }

      double nextDouble()
      {
          return Double.parseDouble(next());
      }

      String nextLine()
      {
          String str = "";
	  try
          {
	     str = br.readLine();
	  } catch (IOException e)
          {
	     e.printStackTrace();
	  }
	  return str;
      }

   }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 *
 * @author Aditya Joshi
 * SPOJ / CodeChef / Codeforces / HackerRank / Timus / UVA
 */
public class Main
{
    private static MyScanner sc;
    private static PrintWriter out;
    private static int[] a;
    private static int[] b;

    public static void main(String[] args)
    {
        sc = new MyScanner();
        out = new PrintWriter(System.out);
        int n = sc.nextInt();
        int[] a = new int[n];
        for(int i = 0; i < n; i++) a[i] = sc.nextInt();
        int m = sc.nextInt();
        int[] b = new int[m];
        for(int i = 0; i < m; i++) b[i] = sc.nextInt();

        Arrays.sort(a);
        Arrays.sort(b);
        long ans_a = 3 * n;
        long ans_b = 3 * m;
        for(int i = 0; i < n; i++)
        {
            int cons = a[i];
            long curr_a = (2 * i) + (3 * (n - i));

            int index_b = binarySearch(b, cons);
            long curr_b = 0;
            if(index_b == -1) curr_b = 2 * m;
            else curr_b = (2 * index_b) + (3 * (m - index_b));
      //      System.out.println("Searching for " + cons + " and found " + index_b);
            if(curr_a - curr_b > (ans_a - ans_b))
            {
                ans_a = curr_a;
                ans_b = curr_b;
            }

        }
        if((2 * n) - (2 * m) > (ans_a - ans_b))
        {
            ans_a = 2 * n;
            ans_b = 2 * m;
        }

        out.println(ans_a + ":" + ans_b);

        out.close();
    }

   public static int binarySearch(int[] a, int key) {
    int low=0,high=a.length-1;
    while (low<=high) {
        if(low + 1 == high)
        {
             if(key == a[high]) return high;
             else if(key == a[low]) return low;
             else if(key > a[high]) return -1;
             else if(key < a[low]) return 0;
             else return low;

        }

        else if(low == high)
        {
            if(key == a[low]) return low;
            else if(key < a[low]) return low;
            else return -1;
        }
        int mid=(low+high) >>> 1;
        int midVal=a[mid];
        if (midVal < key)
            low=mid+1;
        else if (mid>0 && a[mid-1]>=key) //we already know midval>=key here
            high=mid-1;
        else if (midVal==key) //found the 1st key
             return mid;
        else
            return ~mid;      //found insertion point
    }
    return ~(a.length);       //insertion point after everything
}
    private static int max(int a, int b)
    {
        if(a > b) return a;
        else return b;
    }

    private static int min(int a, int b)
    {
        if(a < b) return a;
        else return b;

    }

    private static int abs(int a, int b)
    {
        return (int) Math.abs(a - b);
    }

     public static int modexp(int a, int b, int n)
     {
        if (b == 0) return 1;
        long t = modexp(a, b/2, n);
        long c = (t * t) % n;
        if (b % 2 == 1)
           c = (c * a) % n;
        return (int) c;
    }

 public static class MyScanner
    {
      BufferedReader br;
      StringTokenizer st;

      public MyScanner()
      {
         br = new BufferedReader(new InputStreamReader(System.in));
      }

      String next()
      {
          while (st == null || !st.hasMoreElements())
          {
              try
              {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e)
              {
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      int nextInt()
      {
          return Integer.parseInt(next());
      }

      long nextLong()
      {
          return Long.parseLong(next());
      }

      double nextDouble()
      {
          return Double.parseDouble(next());
      }

      String nextLine()
      {
          String str = "";
	  try
          {
	     str = br.readLine();
	  } catch (IOException e)
          {
	     e.printStackTrace();
	  }
	  return str;
      }

   }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 *
 * @author Aditya Joshi
 * SPOJ / CodeChef / Codeforces / HackerRank / Timus / UVA
 */
public class Main
{
    private static MyScanner sc;
    private static PrintWriter out;
    private static int[] a;
    private static int[] b;

    public static void main(String[] args)
    {
        sc = new MyScanner();
        out = new PrintWriter(System.out);
        int n = sc.nextInt();
        int[] a = new int[n];
        for(int i = 0; i < n; i++) a[i] = sc.nextInt();
        int m = sc.nextInt();
        int[] b = new int[m];
        for(int i = 0; i < m; i++) b[i] = sc.nextInt();

        Arrays.sort(a);
        Arrays.sort(b);
        long ans_a = 3 * n;
        long ans_b = 3 * m;
        for(int i = 0; i < n; i++)
        {
            int cons = a[i];
            long curr_a = (2 * i) + (3 * (n - i));

            int index_b = binarySearch(b, cons);
            long curr_b = 0;
            if(index_b == -1) curr_b = 2 * m;
            else curr_b = (2 * index_b) + (3 * (m - index_b));

            if(curr_a - curr_b > (ans_a - ans_b))
            {
                ans_a = curr_a;
                ans_b = curr_b;
            }

        }
        if(ans_a == 0 && ans_b == 0) out.println((n * 2) + ":" + (m * 2));
        else out.println(ans_a + ":" + ans_b);

        out.close();
    }

   public static int binarySearch(int[] a, int key) {
    int low=0,high=a.length-1;
    while (low<=high) {
        if(low + 1 == high)
        {
             if(key == a[high]) return high;
             else if(key == a[low]) return low;
             else if(key > a[high]) return -1;
             else if(key < a[low]) return 0;
             else return low;

        }

        else if(low == high)
        {
            if(key == a[low]) return low;
            else return -1;
        }
        int mid=(low+high) >>> 1;
        int midVal=a[mid];
        if (midVal < key)
            low=mid+1;
        else if (mid>0 && a[mid-1]>=key) //we already know midval>=key here
            high=mid-1;
        else if (midVal==key) //found the 1st key
             return mid;
        else
            return ~mid;      //found insertion point
    }
    return ~(a.length);       //insertion point after everything
}
    private static int max(int a, int b)
    {
        if(a > b) return a;
        else return b;
    }

    private static int min(int a, int b)
    {
        if(a < b) return a;
        else return b;

    }

    private static int abs(int a, int b)
    {
        return (int) Math.abs(a - b);
    }

     public static int modexp(int a, int b, int n)
     {
        if (b == 0) return 1;
        long t = modexp(a, b/2, n);
        long c = (t * t) % n;
        if (b % 2 == 1)
           c = (c * a) % n;
        return (int) c;
    }

 public static class MyScanner
    {
      BufferedReader br;
      StringTokenizer st;

      public MyScanner()
      {
         br = new BufferedReader(new InputStreamReader(System.in));
      }

      String next()
      {
          while (st == null || !st.hasMoreElements())
          {
              try
              {
                  st = new StringTokenizer(br.readLine());
              } catch (IOException e)
              {
                  e.printStackTrace();
              }
          }
          return st.nextToken();
      }

      int nextInt()
      {
          return Integer.parseInt(next());
      }

      long nextLong()
      {
          return Long.parseLong(next());
      }

      double nextDouble()
      {
          return Double.parseDouble(next());
      }

      String nextLine()
      {
          String str = "";
	  try
          {
	     str = br.readLine();
	  } catch (IOException e)
          {
	     e.printStackTrace();
	  }
	  return str;
      }

   }
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;

#define MAXN  131072
#define MAXLG 19//log of MAXN

char A[MAXN];
struct entry {
    int nr[2], p;
} L[MAXN];

//P[i][j]=2^i  len er kono ekta string jeita j th  smallest oitar pos string e kothay
int P[MAXLG][MAXN];
int  N, stp, cnt;

int cmp(struct entry a, struct entry b)
{
    return a.nr[0] == b.nr[0] ? (a.nr[1] < b.nr[1] ? 1 : 0) : (a.nr[0] < b.nr[0] ? 1 : 0);
}

void suff_array()
{
    int i;
    for (N = strlen(A), i = 0; i < N; i ++)
        P[0][i] = A[i] - 'A';
    for (stp = 1, cnt = 1; cnt >> 1 < N; stp ++, cnt <<= 1)
    {
        for (i = 0; i < N; i ++)
        {
            L[i].nr[0] = P[stp - 1][i];
            L[i].nr[1] = i + cnt < N ? P[stp - 1][i + cnt] : -1;
            L[i].p = i;
        }
        sort(L, L + N, cmp);
        for (i = 0; i < N; i ++)
            P[stp][L[i].p] = i > 0 && L[i].nr[0] == L[i - 1].nr[0] && L[i].nr[1] == L[i - 1].nr[1] ?P[stp][L[i - 1].p] : i;
    }
}

int lcp(int x, int y)
{
    int k, ret = 0;
    if (x == y) return N - x;
    for (k = stp - 1; k >= 0 && x < N && y < N; k --)
        if (P[k][x] == P[k][y])
            x += 1 << k, y += 1 << k, ret += 1 << k;
    return ret;
}

int pos_st[100010];
vector<pair<int,int > > ans;
int main()
{
    //freopen("in.txt","r",stdin);

    int i;

    gets(A);
    suff_array();

    int n=strlen(A);

    for(i=0;i<n;i++)
    {
        pos_st[P[stp-1][i]]=i;
      //      printf("%d\n",P[stp-1][i]);
    }

    //return 0;

    int lo=0;
    int hi=n-1;
    int mid=P[stp-1][0];

    for(i=1;i<=n;i++)
    {
        while(lcp(pos_st[lo],pos_st[mid])<i) lo++;
        while(lcp(pos_st[hi],pos_st[mid])<i) hi--;

        int p= P[stp-1][n-i];

        if(lo<=p && p<=hi)
        {
            //printf("%d %d\n",i,hi-lo+1);
            ans.push_back(make_pair(i,hi-lo+1));
        }
    }

    cout<<ans.size()<<endl;
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;

#define MAXN  131072
#define MAXLG 18//log of MAXN

char A[MAXN];
struct entry {
    int nr[2], p;
} L[MAXN];

//P[i][j]=2^i  len er kono ekta string jeita j th  smallest oitar pos string e kothay
int P[MAXLG][MAXN];
int  N, i, stp, cnt;

int cmp(struct entry a, struct entry b)
{
    return a.nr[0] == b.nr[0] ? (a.nr[1] < b.nr[1] ? 1 : 0) : (a.nr[0] < b.nr[0] ? 1 : 0);
}

void suff_array()
{
    for (N = strlen(A), i = 0; i < N; i ++)
        P[0][i] = A[i] - 'a';
    for (stp = 1, cnt = 1; cnt >> 1 < N; stp ++, cnt <<= 1)
    {
        for (i = 0; i < N; i ++)
        {
            L[i].nr[0] = P[stp - 1][i];
            L[i].nr[1] = i + cnt < N ? P[stp - 1][i + cnt] : -1;
            L[i].p = i;
        }
        sort(L, L + N, cmp);
        for (i = 0; i < N; i ++)
            P[stp][L[i].p] = i > 0 && L[i].nr[0] == L[i - 1].nr[0] && L[i].nr[1] == L[i - 1].nr[1] ?P[stp][L[i - 1].p] : i;
    }
}

int lcp(int x, int y)
{
    int k, ret = 0;
    if (x == y) return N - x;
    for (k = stp - 1; k >= 0 && x < N && y < N; k --)
        if (P[k][x] == P[k][y])
            x += 1 << k, y += 1 << k, ret += 1 << k;
    return ret;
}

int pos_st[100010];
vector<pair<int,int > > ans;
int main()
{
    //freopen("in.txt","r",stdin);

    int i;

    gets(A);
    suff_array();

    int n=strlen(A);

    for(i=0;i<n;i++)
    {
        pos_st[P[stp-1][i]]=i;
      //      printf("%d\n",P[stp-1][i]);
    }

    //return 0;

    int lo=0;
    int hi=n-1;
    int mid=P[stp-1][0];

    for(i=1;i<=n;i++)
    {
        while(lcp(pos_st[lo],pos_st[mid])<i) lo++;
        while(lcp(pos_st[hi],pos_st[mid])<i) hi--;

        int p= P[stp-1][n-i];

        if(lo<=p && p<=hi)
        {
            //printf("%d %d\n",i,hi-lo+1);
            ans.push_back(make_pair(i,hi-lo+1));
        }
    }

    cout<<ans.size()<<endl;
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }

    return 0;
}


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<ctime>
#include<assert.h>

#include<cmath>
#include<iostream>
#include<fstream>

#include<string>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<sstream>
#include<stack>
#include<limits.h>

using namespace std;

#define MAX(a,b) ((a)>(b) ? (a) : (b))
#define MIN(a,b) ((a)<(b) ? (a) : (b))
#define EPS 1e-9
#define asdf exit(0);

//typedef long long LL;

#define MAXN  100000
#define MAXLG 19//to get this val do the MAXLG test
#define MAX_CHAR 26 //A..Z vals are stored in string P[][] will get [0,25]

char A[MAXN+10];
struct entry {
    int nr[2], p;
} L[MAXN+10];

//P[i][j]=2^i  len er kono ekta string jeita j th  smallest oitar pos string e kothay
int P[MAXLG][MAXN+10];
int  N, stp, cnt;

int cmp(const entry &a, const entry &b)
{
    return a.nr[0] == b.nr[0] ? (a.nr[1] < b.nr[1] ? 1 : 0) : (a.nr[0] < b.nr[0] ? 1 : 0);
}

int temp_srt[MAX_CHAR+10];//temporary arr used for count sort
entry L_temp[MAXN+10];

//sort on the bassis of nr[id]
void count_srt(int id)
{
    int i;
    memset(temp_srt,0,(MAX_CHAR+4)*sizeof(int));

    for(i=0;i<N;i++) temp_srt[ L[i].nr[id]+2 ]++;//why2?  somethimes id=-1

    for(i=1;i<=(MAX_CHAR);i++) temp_srt[i]+=temp_srt[i-1];

    for(i=N-1;i>=0;i--)
    {
        temp_srt[ L[i].nr[id]+2 ]--;
        L_temp[ temp_srt[ L[i].nr[id]+2 ] ]=L[i];
    }
    for(i=0;i<N;i++) L[i]=L_temp[i];
}

void suff_array()
{
    int i;

    for (N = strlen(A), i = 0; i < N; i ++)
        P[0][i] = A[i] - 'A';

    for (stp = 1, cnt = 1; cnt >> 1 < N; stp ++, cnt <<= 1)
    {
        for (i = 0; i < N; i ++)
        {
            L[i].nr[0] = P[stp - 1][i];
            L[i].nr[1] = i + cnt < N ? P[stp - 1][i + cnt] : -1;
            L[i].p = i;
        }

        //sort(L, L + N, cmp);

        count_srt(1); //O(N+MAX_CHAR)
        count_srt(0); //O(N+MAX_CHAR)

        for (i = 0; i < N; i ++)
            P[stp][L[i].p] = i > 0 && L[i].nr[0] == L[i - 1].nr[0] && L[i].nr[1] == L[i - 1].nr[1] ?P[stp][L[i - 1].p] : i;
    }

}

void MAXLG_test()
{
    N=MAXN;
    for (stp = 1, cnt = 1; cnt >> 1 < N; stp ++, cnt <<= 1) {}
    cout<<"val of MAXLG "<<stp<<endl;
}

//string er x,y pos er substr er moddhe
int lcp(int x, int y)
{
    int k, ret = 0;
    if (x == y) return N - x;
    for (k = stp - 1; k >= 0 && x < N && y < N; k --)
        if (P[k][x] == P[k][y])
            x += 1 << k, y += 1 << k, ret += 1 << k;
    return ret;
}

/*
int main()
{
    freopen("in.txt","r",stdin);
    //MAXLG_test();

    int i;

    gets(A);
    suff_array();
    for(i=0;i<N;i++)
    {
        //ith pos e jei string ta ase setar relative position in sorted sequence
        printf("%d\n",P[stp-1][i]);
    }
    return 0;
}
*/

int pos_st[100010];
vector<pair<int,int > > ans;
int main()
{
    //freopen("in.txt","r",stdin);

    int i;

    gets(A);
    suff_array();

    int n=strlen(A);

    for(i=0;i<n;i++)
    {
        pos_st[P[stp-1][i]]=i;
      //      printf("%d\n",P[stp-1][i]);
    }

    //return 0;

    int lo=0;
    int hi=n-1;
    int mid=P[stp-1][0];

    for(i=1;i<=n;i++)
    {
        while(lcp(pos_st[lo],pos_st[mid])<i) lo++;
        while(lcp(pos_st[hi],pos_st[mid])<i) hi--;

        int p= P[stp-1][n-i];

        if(lo<=p && p<=hi)
        {
            //printf("%d %d\n",i,hi-lo+1);
            ans.push_back(make_pair(i,hi-lo+1));
        }
    }

    cout<<ans.size()<<endl;
    for(i=0;i<ans.size();i++)
    {
        printf("%d %d\n",ans[i].first,ans[i].second);
    }

    return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
int main(){
    ios_base::sync_with_stdio(0);
    string s;
    cin >> s;
    int n = s.length();
    int l=0,r=0;
    int* z = new int[n];
    int* f = new int[n+1];
    for(int i=0;i<=n;i++) f[i]=0;
    z[0]=n;
    f[n]=1;
    int ct=0;
    for(int i=1;i<n;i++){
    //  cout << i <<endl;
        if(i>r){
            l=i;
            r=i;
            while(r<n && s[r]==s[r-l])r++;
            z[i]=r-l;
            r--;
        }
        else{
            int k=i-l;
            if(z[k]<r-i+1) z[i]=z[k];
            else{
                l=i;
                //r=i;
                while(r<n && s[r]==s[r-l]) r++;
                z[i]=r-l;
                r--;
            }
        }
        if(z[i]==(n-i)) ct++;
        if(z[i]!=0)f[z[i]]++;
    }
    cout << ct+1 << "\n";
    for(int i=n-1;i>=0;i--) f[i]+=f[i+1];
    for(int i=(n-1);i>=0;i--){
        if(z[i]==(n-i)){
            cout << z[i] << " " << f[z[i]] << "\n";
        }
    }
    return 0;
}


#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <cmath>
#include <climits>
#include <string.h>
#include <map>
#include <utility>
using namespace std;
int main(){
    string a;
    cin >> a;

    int k=0;
    for(int i=0;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            k++;
        }
    }
    vector<int> curr;
    vector<int> last;
    cout << k << endl;
    if(a[0]==a[a.length()-1]){
        int ctt = 0;
        for(int i=0;i<a.length();i++) if(a[i]==a[0]) last.push_back(i),ctt++;
        cout << 1 << " " << ctt << endl;
    }
    for(int i=1;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            cout << i+1 << " " ;
            int ct=0;
            for(vector<int>::iterator it=last.begin();it!=last.end();it++){
                if(*it+i<a.length() && a.substr(*it,i+1)==a.substr(a.length()-i-1,i+1)) curr.push_back(*it),ct++;
            }
            cout << ct << endl;
            last = curr;
            curr.clear();
        }
    }
    return 0;
}


#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <cmath>
#include <climits>
#include <string.h>
#include <map>
#include <utility>
using namespace std;
int main(){
    string a;
    cin >> a;

    int k=0;
    for(int i=0;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            k++;
        }
    }
    vector<int> curr;
    vector<int> last;
    cout << k+1 << endl;
    if(a[0]==a[a.length()-1]){
        int ctt = 0;
        for(int i=0;i<a.length();i++) if(a[i]==a[0]) last.push_back(i),ctt++;
        cout << 1 << " " << ctt << endl;
    }
    for(int i=1;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            cout << i+1 << " " ;
            int ct=0;
            for(vector<int>::iterator it=last.begin();it!=last.end();it++){
                if(*it+i<a.length() && a.substr(*it,i+1)==a.substr(a.length()-i-1,i+1)) curr.push_back(*it),ct++;
            }
            cout << ct << endl;
            last = curr;
            curr.clear();
        }
    }
    return 0;
}


#include <cstdio>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <cmath>
#include <climits>
#include <string.h>
#include <map>
#include <utility>
using namespace std;
int main(){
    string a;
    cin >> a;

    int k=0;
    int mm=0;
    for(int i=0;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            k++;
            if(mm==0) mm=i+1;
        }
    }
    vector<int> curr;
    vector<int> last;
    cout << k << endl;
        int ctt = 0;
        for(int i=0;i<a.length()-mm;i++) if(a.substr(i,mm)==a.substr(a.length()-mm,mm)) last.push_back(i),ctt++;
        cout << mm << " " << ctt+1 << endl;
    for(int i=mm;i<a.length();i++){
        if(a.substr(0,i+1)==a.substr(a.length()-i-1,i+1)){
            cout << i+1 << " " ;
            int ct=0;
            for(vector<int>::iterator it=last.begin();it!=last.end();it++){
                if(*it+i<a.length() && a.substr(*it,i+1)==a.substr(a.length()-i-1,i+1)) curr.push_back(*it),ct++;
            }
            cout << ct << endl;
            last = curr;
            curr.clear();
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
int main(){
    ios_base::sync_with_stdio(0);
    string s;
    cin >> s;
    int n = s.length();
    int l=0,r=0;
    int* z = new int[n];
    int* f = new int[n+1];
    for(int i=0;i<=n;i++) f[i]=0;
    z[0]=n;
    f[n]=1;
    int ct=0;
    for(int i=1;i<n;i++){
        if(i>r){
            l=i;
            r=i;
            while(s[r]==s[r-l])r++;
            z[i]=r-l;
            r--;
        }
        else{
            int k=i-l;
            if(z[k]<r-i) z[i]=z[k];
            else{
                l=i;
                r=i;
                while(s[r]==s[r-l]) r++;
                z[i]=r-l;
                r--;
            }
        }
        if(z[i]==(n-i)) ct++;
        if(z[i]!=0)f[z[i]]++;
    }
    cout << ct+1 << "\n";
    for(int i=n-1;i>=0;i--) f[i]+=f[i+1];
    for(int i=(n-1);i>=0;i--){
        if(z[i]==(n-i)){
            cout << z[i] << " " << f[z[i]] << "\n";
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define MOD 1000000007
using namespace std;
int main(){
    ios_base::sync_with_stdio(0);
    string s;
    cin >> s;
    int n = s.length();
    int l=0,r=0;
    int* z = new int[n];
    int* f = new int[n+1];
    for(int i=0;i<=n;i++) f[i]=0;
    z[0]=n;
    f[n]=1;
    int ct=0;
    for(int i=1;i<n;i++){
        if(i>r){
            l=i;
            r=i;
            while(s[r]==s[r-l])r++;
            z[i]=r-l;
            r--;
        }
        else{
            int k=i-l;
            if(z[k]<r-i+1) z[i]=z[k];
            else{
                l=i;
                r=i;
                while(s[r]==s[r-l]) r++;
                z[i]=r-l;
                r--;
            }
        }
        if(z[i]==(n-i)) ct++;
        if(z[i]!=0)f[z[i]]++;
    }
    cout << ct+1 << "\n";
    for(int i=n-1;i>=0;i--) f[i]+=f[i+1];
    for(int i=(n-1);i>=0;i--){
        if(z[i]==(n-i)){
            cout << z[i] << " " << f[z[i]] << "\n";
        }
    }
    return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
typedef long long ll;
typedef unsigned long long ull;
const double error = 1e-15;
const double pi=2*acos(0);
const int maxn = (int)1e5 + 10;
const int mod = (int)1e9;
int dx[]={0,-1,0,+1,-1,-1,+1,+1};
int dy[]={-1,0,+1,0,-1,+1,+1,-1};
 //cout.precision(10);
//cout<<fixed<<hor*1.0/lob<<endl;
// if (fabs(a-b)<ERROR) printf( "They are equal\n" );

int Pi[100005],q=2;
void Prefix_function(string p)
{
    int m,k;
    m=p.size();
   // for(q=0;q<=m;q++)
    //Pi[q]=0;
    Pi[1]=0;
    k=0;
    for(;q<=m;q++)
    {
        while(k>0&&p[k]!=p[q-1])
        k=Pi[k];
        if(p[k]==p[q-1])
        k=k+1;
        Pi[q]=k;
    }
}
int suf=0;
int KMP(string T,string P)
{
    int n,m,k,i,cnt=0;
    n=T.size();
    m=P.size();
    Prefix_function(P);
    k=0;
    for(i=1;i<=n;i++)
    {
        while(k>0&&P[k]!=T[i-1])
        k=Pi[k];
        if(P[k]==T[i-1])
        k=k+1;
        if(k==m)
        {
            //cout<<"Pattern occurs with shift "<<i-m<<endl;
           // q=Pi[q];
           suf=i;
           cnt++;
        }
    }
    return cnt;
}
vector<pii>ans;
int z[100005];
void Z_algorithm(string s)
{

    int L = 0, R = 0,n,p;
    n=s.size();
for (int i = 1; i < n; i++)
{
  if (i > R)
  {
    L = R = i;
    while (R < n && s[R-L] == s[R])
    R++;
    z[i] = R-L; R--;
  }
  else
  {
    int k = i-L;
    if (z[k] < R-i+1)
    z[i] = z[k];
    else
    {
      L = i;
      while (R < n && s[R-L] == s[R])
       R++;
      z[i] = R-L; R--;
    }
  }
  //cout<<z[i]<<" ";
}
}
int main(){
//char T[1000],P[1000];
long i,j,l,x;
string st,tmp;
cin>>st;
l=st.size();
Z_algorithm(st);
tmp="";
j=l-1;
for(i=0;i<l;i++)
{
   tmp=tmp+st[i];

   if(l-j==z[j])
   {
    x=KMP(st,tmp);
    ans.pb(mp(i+1,x));
   }
   j--;
}
ans.pb(mp(l,1));
cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i].f<<" "<<ans[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
typedef long long ll;
typedef unsigned long long ull;
const double error = 1e-15;
const double pi=2*acos(0);
const int maxn = (int)1e5 + 10;
const int mod = (int)1e9;
int dx[]={0,-1,0,+1,-1,-1,+1,+1};
int dy[]={-1,0,+1,0,-1,+1,+1,-1};
 //cout.precision(10);
//cout<<fixed<<hor*1.0/lob<<endl;
// if (fabs(a-b)<ERROR) printf( "They are equal\n" );

int Pi[100005];
void Prefix_function(string p)
{
    int m,k,q;
    m=p.size();
   // for(q=0;q<=m;q++)
    //Pi[q]=0;
    Pi[1]=0;
    k=0;
    for(q=2;q<=m;q++)
    {
        while(k>0&&p[k]!=p[q-1])
        k=Pi[k];
        if(p[k]==p[q-1])
        k=k+1;
        Pi[q]=k;
    }
}
int suf=0;
int KMP(string T,string P)
{
    int n,m,k,i,cnt=0;
    n=T.size();
    m=P.size();
    Prefix_function(P);
    k=0;
    for(i=1;i<=n;i++)
    {
        while(k>0&&P[k]!=T[i-1])
        k=Pi[k];
        if(P[k]==T[i-1])
        k=k+1;
        if(k==m)
        {
            //cout<<"Pattern occurs with shift "<<i-m<<endl;
           // q=Pi[q];
           suf=i;
           cnt++;
        }
    }
    return cnt;
}
vector<pii>ans;
int z[100005];
void Z_algorithm(string s)
{

    int L = 0, R = 0,n,p;
    n=s.size();
for (int i = 1; i < n; i++)
{
  if (i > R)
  {
    L = R = i;
    while (R < n && s[R-L] == s[R])
    R++;
    z[i] = R-L; R--;
  }
  else
  {
    int k = i-L;
    if (z[k] < R-i+1)
    z[i] = z[k];
    else
    {
      L = i;
      while (R < n && s[R-L] == s[R])
       R++;
      z[i] = R-L; R--;
    }
  }
  //cout<<z[i]<<" ";
}
}
int main(){
//char T[1000],P[1000];
long i,j,l,x;
string st,tmp;
cin>>st;
l=st.size();
Z_algorithm(st);
tmp="";
j=l-1;
for(i=0;i<l;i++)
{
   tmp=tmp+st[i];

   if(l-j==z[j])
   {
    x=KMP(st,tmp);
    ans.pb(mp(i+1,x));
   }
   j--;
}
ans.pb(mp(l,1));
cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i].f<<" "<<ans[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
typedef long long ll;
typedef unsigned long long ull;
const double error = 1e-15;
const double pi=2*acos(0);
const int maxn = (int)1e5 + 10;
const int mod = (int)1e9;
int dx[]={0,-1,0,+1,-1,-1,+1,+1};
int dy[]={-1,0,+1,0,-1,+1,+1,-1};
 //cout.precision(10);
//cout<<fixed<<hor*1.0/lob<<endl;
// if (fabs(a-b)<ERROR) printf( "They are equal\n" );

int Pi[100005],q=2,kk=0;
void Prefix_function(string p)
{
    int m,k;
    m=p.size();
   // for(q=0;q<=m;q++)
    //Pi[q]=0;
    Pi[1]=0;
    //k=0;
    for(;q<=m;q++)
    {
        while(kk>0&&p[kk]!=p[q-1])
        kk=Pi[kk];
        if(p[kk]==p[q-1])
        kk=kk+1;
        Pi[q]=kk;
    }
}
int suf=0;
int KMP(string T,string P)
{
    int n,m,k,i,cnt=0;
    n=T.size();
    m=P.size();
    Prefix_function(P);
    k=0;
    for(i=1;i<=n;i++)
    {
        while(k>0&&P[k]!=T[i-1])
        k=Pi[k];
        if(P[k]==T[i-1])
        k=k+1;
        if(k==m)
        {
            //cout<<"Pattern occurs with shift "<<i-m<<endl;
           // q=Pi[q];
           suf=i;
           cnt++;
        }
    }
    return cnt;
}
vector<pii>ans;
int z[100005];
void Z_algorithm(string s)
{

    int L = 0, R = 0,n,p;
    n=s.size();
for (int i = 1; i < n; i++)
{
  if (i > R)
  {
    L = R = i;
    while (R < n && s[R-L] == s[R])
    R++;
    z[i] = R-L; R--;
  }
  else
  {
    int k = i-L;
    if (z[k] < R-i+1)
    z[i] = z[k];
    else
    {
      L = i;
      while (R < n && s[R-L] == s[R])
       R++;
      z[i] = R-L; R--;
    }
  }
  //cout<<z[i]<<" ";
}
}
int main(){
//char T[1000],P[1000];
long i,j,l,x;
string st,tmp;
cin>>st;
l=st.size();
Z_algorithm(st);
tmp="";
j=l-1;
for(i=0;i<l;i++)
{
   tmp=tmp+st[i];

   if(l-j==z[j])
   {
    x=KMP(st,tmp);
    ans.pb(mp(i+1,x));
   }
   j--;
}
ans.pb(mp(l,1));
cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i].f<<" "<<ans[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
typedef long long ll;
typedef unsigned long long ull;
const double error = 1e-15;
const double pi=2*acos(0);
const int maxn = (int)1e5 + 10;
const int mod = (int)1e9;
int dx[]={0,-1,0,+1,-1,-1,+1,+1};
int dy[]={-1,0,+1,0,-1,+1,+1,-1};
 //cout.precision(10);
//cout<<fixed<<hor*1.0/lob<<endl;
// if (fabs(a-b)<ERROR) printf( "They are equal\n" );

int Pi[100005];
void Prefix_function(string p)
{
    int m,k,q;
    m=p.size();
   // for(q=0;q<=m;q++)
    //Pi[q]=0;
    Pi[1]=0;
    k=0;
    for(q=2;q<=m;q++)
    {
        while(k>0&&p[k]!=p[q-1])
        k=Pi[k];
        if(p[k]==p[q-1])
        k=k+1;
        Pi[q]=k;
    }
}
int suf=0;
int KMP(string T,string P)
{
    int n,m,k,i,cnt=0;
    n=T.size();
    m=P.size();
    Prefix_function(P);
    k=0;
    for(i=1;i<=n;i++)
    {
        while(k>0&&P[k]!=T[i-1])
        k=Pi[k];
        if(P[k]==T[i-1])
        k=k+1;
        if(k==m)
        {
            //cout<<"Pattern occurs with shift "<<i-m<<endl;
           // q=Pi[q];
           suf=i;
           cnt++;
        }
    }
    return cnt;
}
vector<pii>ans;
int main(){
//char T[1000],P[1000];
long i,j,l,x;
string st,tmp;
cin>>st;
l=st.size();
j=l-1;
tmp="";
for(i=0;i<l;i++)
{
   tmp=tmp+st[i];
   x=st.find(tmp,l-i-1);
   if(x>=0&&x<l)
   {
   suf=-1;
    x=KMP(st,tmp);
    if(suf==l)
    ans.pb(mp(i+1,x));
   }
}

cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i].f<<" "<<ans[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
typedef long long ll;
typedef unsigned long long ull;
const double error = 1e-15;
const double pi=2*acos(0);
const int maxn = (int)1e5 + 10;
const int mod = (int)1e9;
int dx[]={0,-1,0,+1,-1,-1,+1,+1};
int dy[]={-1,0,+1,0,-1,+1,+1,-1};
 //cout.precision(10);
//cout<<fixed<<hor*1.0/lob<<endl;
// if (fabs(a-b)<ERROR) printf( "They are equal\n" );

int Pi[100005];
void Prefix_function(string p)
{
    int m,k,q;
    m=p.size();
   // for(q=0;q<=m;q++)
    //Pi[q]=0;
    Pi[1]=0;
    k=0;
    for(q=2;q<=m;q++)
    {
        while(k>0&&p[k]!=p[q-1])
        k=Pi[k];
        if(p[k]==p[q-1])
        k=k+1;
        Pi[q]=k;
    }
}
int suf=0;
int KMP(string T,string P)
{
    int n,m,k,i,cnt=0;
    n=T.size();
    m=P.size();
    Prefix_function(P);
    k=0;
    for(i=1;i<=n;i++)
    {
        while(k>0&&P[k]!=T[i-1])
        k=Pi[k];
        if(P[k]==T[i-1])
        k=k+1;
        if(k==m)
        {
            //cout<<"Pattern occurs with shift "<<i-m<<endl;
           // q=Pi[q];
           suf=i;
           cnt++;
        }
    }
    return cnt;
}
vector<pii>ans;
int main(){
//char T[1000],P[1000];
long i,j,l,x;
string st,tmp;
cin>>st;
l=st.size();
j=l-1;
tmp="";
for(i=0;i<l;i++)
{
   tmp=tmp+st[i];
   suf=-1;
    x=KMP(st,tmp);
    if(suf==l)
    ans.pb(mp(i+1,x));
    j--;
}

cout<<ans.size()<<endl;
for(i=0;i<ans.size();i++)
cout<<ans[i].f<<" "<<ans[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
vector<pii>v;
int dp[100005];
int main(){
    char s[100005];
    int L = 0, R = 0,n,max=0,z[100005],p,j,pr=0;
    scanf("%s",s);
    n=strlen(s);
for (int i = 1; i < n; i++)
{
  if (i > R)
  {
    L = R = i;
    while (R < n && s[R-L] == s[R])
    R++;
    z[i] = R-L; R--;
    if(z[i]>max)
    {
        p=i;
        max=z[i];
    }
  }
  else
  {
    int k = i-L;
    if (z[k] < R-i+1)
    z[i] = z[k];
    else
    {
      L = i;
      while (R < n && s[R-L] == s[R])
       R++;
      z[i] = R-L; R--;
      if(z[i]>max)
      {
        p=i;
        max=z[i];
      }
    }
  }
  dp[z[i]]++;

}
v.pb(mp(n,1));
for(int i=n-1;i>0;i--)
{
    dp[i-1]=dp[i-1]+dp[i];
}
for(int i=n-1;i>0;i--)
{
    if(z[i]+i==n)
    {
      v.pb(mp(z[i],dp[z[i]]+1));
    }
}

sort(v.begin(),v.end());
cout<<v.size()<<endl;
for(int i=0;i<v.size();i++)
cout<<v[i].f<<" "<<v[i].s<<endl;
return 0;
}


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

#define sz(x) ((int)(x).size())
#define ms0(x) memset(x,0,sizeof(x))
#define ms1(x) memset(x,-1,sizeof(x))
#define ms2(x) memset(x,10,sizeof(x))
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define inf 1001001001
typedef pair<int,int> pii;
typedef pair<int,pair<int,int> > piii;
vector<pii>v;
int dp[100005];
int main(){
    char s[100005];
    int L = 0, R = 0,n,max=0,z[100005],p,j,pr=0;
    scanf("%s",s);
    n=strlen(s);
for (int i = 1; i < n; i++)
{
  if (i > R)
  {
    L = R = i;
    while (R < n && s[R-L] == s[R])
    R++;
    z[i] = R-L; R--;
    if(z[i]>max)
    {
        p=i;
        max=z[i];
    }
  }
  else
  {
    int k = i-L;
    if (z[k] < R-i+1)
    z[i] = z[k];
    else
    {
      L = i;
      while (R < n && s[R-L] == s[R])
       R++;
      z[i] = R-L; R--;
      if(z[i]>max)
      {
        p=i;
        max=z[i];
      }
    }
  }
  dp[z[i]]++;
  if(z[i]+i==n)
  {
      v.pb(mp(z[i],pr+dp[z[i]]+1));
      pr+=dp[z[i]];
      //for(j=1;j<z[i];j++)
      //dp[j]+=dp[z[i]];
  }
}
v.pb(mp(n,1));
sort(v.begin(),v.end());
cout<<v.size()<<endl;
for(int i=0;i<v.size();i++)
cout<<v[i].f<<" "<<v[i].s<<endl;
return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define fr first
#define sc second
#define mod 1000000007
using namespace std;

vector<int>fail(string s){
    int n = s.length();
    vector<int>res(n);
    res[0] = 0;
    for(int i=1,k=0 ; i<n ; i++){
        while(k>0 && s[i]!=s[k]) k = res[k-1];
        if(s[i] == s[k])k++;
        res[i] = k;
    }
    return res;
}

int kmp(string s1,string s2){
    vector<int>f = fail(s2);
    int n=s1.length(),l=s2.length();
    int r=0;
    for(int i=0,k=0 ; i<n ; i++){
        while(k>0 && s1[i] != s2[k])k = f[k-1];
        if(s1[i] == s2[k])k++;
        if(k == l)
            r++;
    }
    return r;
}

bool pal(string s){
    int n =s.length();
    for(int i=0 ; i<n/2 ;i++){
        if(s[i] != s[n-i-1])return 0;
    }
    return 1;
}

int main(){
    string s,pre="",suf="",t = "";
    cin>>s;
    int n = s.length(),k=0;
    pair<int,int>res[n];
    for(int i=0 ; i<n ; i++){
        pre += s[i];
        suf = s[n-i-1]+suf;
        if(pre == suf){
            res[k++] = make_pair(i+1,kmp(s,pre));
        }
    }
    cout<<k;
    for(int i=0 ; i<k ; i++){
        cout<<endl<<res[i].fr<<" "<<res[i].sc;
    }
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define fr first
#define sc second
#define mod 1000000007
using namespace std;

vector<int>fail(string s){
    int n = s.length();
    vector<int>res(n);
    res[0] = 0;
    for(int i=1,k=0 ; i<n ; i++){
        while(k>0 && s[i]!=s[k]) k = res[k-1];
        if(s[i] == s[k])k++;
        res[i] = k;
    }
    return res;
}

int kmp(string s1,string s2){
    vector<int>f = fail(s2);
    int n=s1.length(),l=s2.length();
    int r=0;
    for(int i=0,k=0 ; i<n ; i++){
        while(k>0 && s1[i] != s2[k])k = f[k-1];
        if(s1[i] == s2[k])k++;
        if(k == l)
            r++;
    }
    return r;
}

bool pal(string s){
    int n =s.length();
    for(int i=0 ; i<n/2 ;i++){
        if(s[i] != s[n-i-1])return 0;
    }
    return 1;
}

int main(){
    string s,s1,t = "";
    cin>>s;
    int n = s.length(),k=0;
    pair<int,int>res[n];
    for(int i=0 ; i<n ; i++){
        if(s[i] != s[n-i-1])break;
        t.push_back(s[i]);
        if(pal(t)){
            res[k++] = make_pair(i+1,kmp(s,t));
        }
    }
    cout<<k;
    for(int i=0 ; i<k ; i++){
        cout<<endl<<res[i].fr<<" "<<res[i].sc;
    }
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define fr first
#define sc second
#define mod 1000000007
using namespace std;

vector<int>fail(string s){
    int n = s.length();
    vector<int>res(n);
    res[0] = 0;
    for(int i=1,k=0 ; i<n ; i++){
        while(k>0 && s[i]!=s[k]) k = res[k-1];
        if(s[i] == s[k])k++;
        res[i] = k;
    }
    return res;
}

int kmp(string s1,string s2){
    vector<int>f = fail(s2);
    int n=s1.length(),l=s2.length();
    int r=0;
    for(int i=0,k=0 ; i<n ; i++){
        while(k>0 && s1[i] != s2[k])k = f[k-1];
        if(s1[i] == s2[k])k++;
        if(k == l)
            r++;
    }
    return r;
}

int main(){
    string s,s1,t = "";
    cin>>s;
    int n=s.length(),k=0;
    string pre[n];
    string suf[n];
    pair<int,int>res[n];
    for(int i=0 ; i<n ; i++){
        t.push_back(s[i]);
        s1.push_back(s[n-1-i]);
        pre[i] = t;
        suf[i] = s1;
        reverse(suf[i].begin(),suf[i].end());
    }
    for(int i=0 ; i<n ; i++){
        if(pre[i] == suf[i])
            res[k++]=make_pair(i+1,kmp(s,pre[i]));
    }
    cout<<k;
    for(int i=0 ; i<k ;i++){
        cout<<endl;
        cout<<res[i].fr<<" "<<res[i].sc;
    }
    return 0;
}


#include <bits/stdc++.h>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define fr first
#define sc second
#define ll  long long
#define mp make_pair
using namespace std;

vector<int>fail(string s){
    int n= s.length();
    vector<int>res(n);
    res[0] = 0;
    for(int i=1,k=0 ; i<n ; i++){
        while(k>0 && s[i] != s[k])
            k = res[k-1];
        if(s[i] == s[k])k++;
        res[i] = k;
    }
    return res;
}
int a[100100];
vector<int>p[100100];

int dfs(int x){
    int r=0;
    for(int i=0 ; i<p[x].size() ; i++){
        r += dfs(p[x][i]);
    }
    a[x] = r;
    return r+1;
}
vector<int>f;
vector<pii>v;
void f1(int x){
    if(x == 0)return;
    f1(f[x-1]);
    v.push_back(mp(x,a[x]+1));
}

int main(){
    ios::sync_with_stdio(0);
    string s;
    cin>>s;
    int n = s.length();

    f = fail(s);

    for(int i=0 ; i<n ; i++){
        p[f[i]].push_back(i+1);
    }

    dfs(0);

    f1(s.length());
    cout<<v.size()<<endl;
    for(int i=0 ; i<v.size(); i ++){
        printf("%d %d\n",v[i].fr,v[i].sc);
    }

    return 0;
}


#include <bits/stdc++.h>
#define pii pair<int,int>
#define pll pair<ll,ll>
#define fr first
#define sc second
#define ll  long long
#define mp make_pair
using namespace std;

vector<int>fail(string s){
    int n= s.length();
    vector<int>res(n);
    res[0] = 0;
    for(int i=1,k=0 ; i<n ; i++){
        while(k>0 && s[i] != s[k])
            k = res[k-1];
        if(s[i] == s[k])k++;
        res[i] = k;
    }
    return res;
}
int a[100100];
vector<int>p[100100];

int dfs(int x){
    int r=0;
    for(int i=0 ; i<p[x].size() ; i++){
        r += dfs(p[x][i]);
    }
    a[x] = r;
    return r+1;
}
vector<int>f;
void f1(int x){
    if(x == 0)return;
    f1(f[x-1]);
    printf("%d %d\n",x,a[x]+1);
}

int main(){
    ios::sync_with_stdio(0);
    string s;
    cin>>s;
    int n = s.length();

    f = fail(s);

    for(int i=0 ; i<n ; i++){
        p[f[i]].push_back(i+1);
    }

    dfs(0);

    f1(s.length());

    return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 100005
using namespace std;

int next[maxn];
char str[maxn];
char txt[maxn];

void getnext(int len)
{
    next[0]=0;next[1]=0;
    for(int i=1;i<len;i++)
    {
        int j=next[i];
        while(j && str[j]!=str[i])j=next[j];
        next[i+1]=str[j]==str[i]?j+1:0;
    }
}

int kmp(int n,int len)
{
    int ans=0;
    getnext(n);

    int j=0;
    for(int i=0;i<n;i++)
    {
        while(j&&txt[j]!=str[i])j=next[j];
        if(txt[j]==str[i])j++;
        if(j==len)ans++;
    }
    return ans;
}
struct node
{
    int len;
    int time;
    bool operator < (const node &cmp)const
    {
        return len<cmp.len;
    }
}fans[maxn];
int top=0;
int cnt[maxn];

void solve(int n)
{
    int j=n;

    for(int i=n;i>=1;i--)
    {
        int j=i;
        int ans=0;
        while(j)
        {
           // ans++;
            cnt[j]++;
            j=next[j];
        }
     //   cnt[j]+=ans>=1;
    }
    j=next[n];
    while(j)
    {
        fans[top].len=j;
        fans[top++].time=cnt[j];
        j=next[j];
    }
    sort(fans,fans+top);
    printf("%d\n",top+1);
    for(int i=0;i<top;i++)
        printf("%d %d\n",fans[i].len,fans[i].time);
    printf("%d %d\n",n,1);
}
int main()
{
    scanf("%s",str);
    int n=strlen(str);
    getnext(n);

    solve(n);

    return 0;
}


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 300005
#define debug puts("here!")
using namespace std;

char str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int cnt[maxn];
int vis[maxn];
int f[maxn][30];

void RMQINIT()
{
    for(int i=0;i<n;i++)
    f[i][0]=height[i];

    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

int RMQ(int l,int r)
{
    int k=floor(log(r-l+1.0)/log(2.0));
    return min(f[l][k],f[r+1-(1<<k)][k]);
}

void solve()
{
   // printf("%d\n",n);
    memset(cnt,0,sizeof cnt);
    memset(vis,0,sizeof vis);
    RMQINIT();
    int len=0;
    for(int i=rank[0];i>0;i--)
    {
       // printf("i = %d height = %d sa[i-1] = %d\n",i,height[i],sa[i-1]);
        if(height[i]+sa[i-1]==n-1)
        {
            //printf("i = %d rank[0] = %d RMQ = %d\n",i,rank[0],RMQ(i,rank[0]));
            len=max(RMQ(i,rank[0]),len);
            //break;
        }
    }
    for(int i=rank[0]+1;i<n;i++)
    {
        if(height[i]+sa[i] == n-1)
        {
            //printf("%d\n",RMQ(rank[0]+1,i));
            len=max(RMQ(rank[0]+1,i),len);
            //break;
        }
    }
    for(int i=rank[0];i>0;i--)
    {
        if(height[i]==0)break;
        if(height[i]+sa[i-1]==n-1)vis[height[i]]=1;
        if(height[i]>=len)cnt[len]++;
        else cnt[height[i]]++;
    }
    for(int i=rank[0]+1;i<n;i++)
    {
        if(height[i]==0)break;
        if(height[i]+sa[i]==n-1)vis[height[i]]=1;
        if(height[i]>=len)cnt[len]++;
        else cnt[height[i]]++;
    }
   /* for(int i=1;i<=len;i++)
        printf("%d ",cnt[i]);
    puts("");*/
    int ans=0;
    if(vis[len])ans++;
    for(int i=len-1;i>=1;i--)
    {
        if(vis[i])ans++;
        cnt[i]+=cnt[i+1];
    }

    printf("%d\n",ans+1);
    for(int i=1;i<=len;i++)
    {
        if(!vis[i])continue;
        printf("%d %d\n",i,cnt[i]+1);
    }
    printf("%d %d\n",n-1,1);
}
int main()
{
    scanf("%s",str);
    n=strlen(str);
    str[n]=0;
    n++;

    suffix(128);
    getheight();

    solve();
    return 0;
}
/*
GERALDPAVELGERALDPAVEL

aaaaaxaaaaaaaaaa
*/


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 300005
#define debug puts("here!")
using namespace std;

char str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int cnt[maxn];
int vis[maxn];
int f[maxn][30];

void RMQINIT()
{
    for(int i=0;i<n;i++)
    f[i][0]=height[i];

    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

int RMQ(int l,int r)
{
    int k=floor(log(r-l+1.0)/log(2.0));
    return min(f[l][k],f[r+1-(1<<k)][k]);
}
struct node
{
    int len,time;
}fans[maxn];
int top=0;
void solve()
{
    RMQINIT();

    for(int i=1;i<n;i++)
    {
        int l,r;

        if( i<rank[0] )
            l=i+1,r=rank[0];
        else if(i>rank[0]) l=rank[0]+1,r=i;
        else continue;

        int comlen=RMQ(l,r);
      //  printf("len = %d\n",comlen);
        if( sa[i] + comlen == n-1 )
        {
            int L=i,R=n-1,ans;
            while(L<=R)
            {
                int mid=(L+R)>>1;
              //  printf("%d\n",RMQ(i+1,mid));
                if(RMQ(i+1,mid)>=comlen)
                {
                    ans=mid;
                    L=mid+1;
                }
                else R=mid-1;
            }

            fans[top].len=comlen;
            fans[top++].time=ans-i+1;
        }
    }
    fans[top].len=n-1;
    fans[top++].time=1;
    for(int i=0;i<top;i++)
        printf("%d %d\n",fans[i].len,fans[i].time);
}
int main()
{
    scanf("%s",str);
    n=strlen(str);
    str[n]=0;
    n++;

    suffix(128);
    getheight();

    solve();
    return 0;
}
/*
GERALDPAVELGERALDPAVEL

aaaaaxaaaaaaaaaa
*/


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 300005
#define debug puts("here!")
using namespace std;

char str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int cnt[maxn];
int vis[maxn];

void solve()
{
    bool found=false;
    for(int i=1; i<n; i++)
    {
        if(height[i] ==0 )
        {
            if(found)
            {
                for(int i=n-1; i>=1; i--)
                {
                    cnt[i]+=cnt[i+1];
                }
                for(int i=1; i<n; i++)
                {
                    if(vis[i])printf("%d %d\n",i,cnt[i]+1);
                }
                printf("%d %d\n",n-1,1);
                return;
            }
            else
            {
                memset(cnt,0,sizeof cnt);
                memset(vis,0,sizeof vis);
                if(sa[i]==0)found=true;
            }
        }
        else
        {
            if(sa[i]==0)found=true;
            vis[height[i]]=1;
            cnt[height[i]]++;
        }
    }
    if(found)
    {
        for(int i=n-1; i>=1; i--)
        {
            cnt[i]+=cnt[i+1];
        }
        for(int i=1; i<n; i++)
        {
            if(vis[i])printf("%d %d\n",i,cnt[i]+1);
        }
        printf("%d %d\n",n-1,1);
    }
}
int main()
{
    scanf("%s",str);
    n=strlen(str);
    str[n]=0;
    n++;

    suffix(128);
    getheight();

    solve();
    return 0;
}


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 100005
using namespace std;

int next[maxn];
char str[maxn];
char txt[maxn];

void getnext(int len)
{
    next[0]=0;next[1]=0;
    for(int i=1;i<len;i++)
    {
        int j=next[i];
        while(j && str[j]!=str[i])j=next[j];
        next[i+1]=str[j]==str[i]?j+1:0;
    }
}

int kmp(int n,int len)
{
    int ans=0;
    getnext(n);

    int j=0;
    for(int i=0;i<n;i++)
    {
        while(j&&txt[j]!=str[i])j=next[j];
        if(txt[j]==str[i])j++;
        if(j==len)ans++;
    }
    return ans;
}
struct node
{
    int len;
    int time;
    bool operator < (const node &cmp)const
    {
        return len<cmp.len;
    }
}fans[maxn];
int top=0;
int cnt[maxn];

void solve(int n)
{
    int j=n;
    for(int i=0;i<=n;i++)
        cnt[i]=1;

    for(int i=n;i>=1;i--)
    {
        int j=i;
        if(next[j])
            cnt[next[j]]+=cnt[j];
    }
    j=next[n];
    while(j)
    {
        fans[top].len=j;
        fans[top++].time=cnt[j];
        j=next[j];
    }
    sort(fans,fans+top);
    printf("%d\n",top+1);
    for(int i=0;i<top;i++)
        printf("%d %d\n",fans[i].len,fans[i].time);
    printf("%d %d\n",n,1);
}
int main()
{
    scanf("%s",str);
    int n=strlen(str);
    getnext(n);

    solve(n);

    return 0;
}


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 300005
#define debug puts("here!")
using namespace std;

char str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int cnt[maxn];
int vis[maxn];

void solve()
{
  //  printf("%d\n",n);
    memset(cnt,0,sizeof cnt);
    memset(vis,0,sizeof vis);
    //for(int i=1;i<n;i++)
     //   printf("%d ",height[i]);
   // puts("");
    int len=height[rank[0]];
    for(int i=rank[0];i>0;i--)
    {
        if(height[i]==0)break;
        if(height[i]+sa[i-1]==n-1)vis[height[i]]=1;
        if(height[i]>=len)cnt[len]++;
        else cnt[height[i]]++;
    }
    for(int i=rank[0]+1;i<n;i++)
    {
        if(height[i]==0)break;
        if(height[i]+sa[i-1]==n-1)vis[height[i]]=1;
        if(height[i]>=len)cnt[len]++;
        else cnt[height[i]]++;
    }
   /* for(int i=1;i<=len;i++)
        printf("%d ",cnt[i]);
    puts("");*/
    for(int i=len-1;i>=1;i--)
        cnt[i]+=cnt[i+1];

    printf("%d\n",len+1);
    int ans=0;
    for(int i=1;i<=len;i++)
    {
        if(!vis[i])continue;
        printf("%d %d\n",i,cnt[i]+1);
    }
    printf("%d %d\n",n-1,1);
}
int main()
{
    scanf("%s",str);
    n=strlen(str);
    str[n]=0;
    n++;

    suffix(128);
    getheight();

    solve();
    return 0;
}
/*
aaaaaxaaaaaaaaaa
*/


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define maxn 300005
#define debug puts("here!")
using namespace std;

char str[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn],n;
void suffix(int m)
{
    int *x=t1,*y=t2;
    for(int i=0; i<m; i++)c[i]=0;
    for(int i=0; i<n; i++)c[x[i]=str[i]]++;
    for(int i=1; i<m; i++)c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--)sa[--c[x[i]]]=i;
    for(int k=1; k<=n; k<<=1)
    {
        int p=0;
        for(int i=n-k; i<n; i++)y[p++]=i;
        for(int i=0; i<n; i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(int i=0; i<m; i++)c[i]=0;
        for(int i=0; i<n; i++)c[x[y[i]]]++;
        for(int i=0; i<m; i++)c[i]+=c[i-1];
        for(int i=n-1; i>=0; i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(int i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
int rank[maxn],height[maxn];
void getheight()
{
    int k=0;
    for(int i=0; i<n; i++)rank[sa[i]]=i;
    for(int i=0; i<n; i++)
    {
        if(k)k--;
        if(!rank[i])continue;
        int j=sa[rank[i]-1];
        while(str[i+k]==str[j+k])k++;
        height[rank[i]]=k;
    }
}

int cnt[maxn];
int vis[maxn];
int f[maxn][30];

void RMQINIT()
{
    for(int i=0;i<n;i++)
    f[i][0]=height[i];

    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}

int RMQ(int l,int r)
{
    if(l==r)return n-1-sa[l];
    if(l>r)swap(l,r);
    l++;
    int k=floor(log(r-l+1.0)/log(2.0));
    return min(f[l][k],f[r+1-(1<<k)][k]);
}
struct node
{
    int len,time;
}fans[maxn];
int top=0;
void solve()
{
    RMQINIT();

    for(int i=1;i<n;i++)
    {
        int l,r;

        if( i<rank[0] )
            l=i,r=rank[0];
        else if(i>rank[0]) l=rank[0],r=i;
        else continue;

        int comlen=RMQ(l,r);

       // printf("len = %d\n",comlen);
        if( sa[i] + comlen == n-1 )
        {
        //    if(sa[i]==4)printf("i=%d\n",i);
            int L=i,R=n-1,ans;
            while(L<=R)
            {
                int mid=(L+R)>>1;
               // if(sa[i]==4)printf("%d %d\n",L,R);
            //    if(sa[i]==4)printf("i = %d mid = %d RMQ = %d\n",i ,mid , RMQ(i,mid));
                if(RMQ(i,mid)>=comlen)
                {
                    ans=mid;
                 //   if(sa[i]==4)printf("ans = %d\n",ans);
                    L=mid+1;
                }
                else R=mid-1;
            }
           // if(sa[i]==4)printf("%d\n",ans);
            fans[top].len=comlen;
            fans[top++].time=ans-i+1;
        }
    }
    fans[top].len=n-1;
    fans[top++].time=1;
    printf("%d\n",top);
    for(int i=0;i<top;i++)
        printf("%d %d\n",fans[i].len,fans[i].time);
}
int main()
{
    scanf("%s",str);
    n=strlen(str);
    str[n]=0;
    n++;

    suffix(128);
    getheight();

    solve();
    return 0;
}
/*
GERALDPAVELGERALDPAVEL

aaaaaxaaaaaaaaaa
*/


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define maxn 100005
using namespace std;

int next[maxn];
char str[maxn];
char txt[maxn];

void getnext(int len)
{
    next[0]=0;next[1]=0;
    for(int i=1;i<len;i++)
    {
        int j=next[i];
        while(j && str[j]!=str[i])j=next[j];
        next[i+1]=str[j]==str[i]?j+1:0;
    }
}

int kmp(int n,int len)
{
    int ans=0;
    getnext(n);

    int j=0;
    for(int i=0;i<n;i++)
    {
        while(j&&txt[j]!=str[i])j=next[j];
        if(txt[j]==str[i])j++;
        if(j==len)ans++;
    }
    return ans;
}
struct node
{
    int len;
    int time;
    bool operator < (const node &cmp)const
    {
        return len<cmp.len;
    }
}fans[maxn];
int top=0;

int main()
{
    scanf("%s",str);
    int n=strlen(str);
    getnext(n);

    int tmp=next[n];
    for(int i=0;i<tmp;i++)
        txt[i]=str[i];
    txt[tmp]='\0';
    while(tmp)
    {
        fans[top].len=tmp;
        fans[top++].time=kmp(n,tmp);
        tmp=next[tmp];
        txt[tmp]='\0';
    }
    sort(fans,fans+top);
    printf("%d\n",top+1);
    for(int i=0;i<top;i++)
        printf("%d %d\n",fans[i].len,fans[i].time);
    printf("%d %d\n",n,1);
    return 0;
}