Coloring of the vertices of a tree G is called a good coloring when, for every pair of two vertices u and v painted in the same color, picking u as the root and picking v as the root would result in isomorphic rooted trees.

Also, the colorfulness of G is defined as the minimum possible number of different colors used in a good coloring of G.

You are given a tree with N vertices. The vertices are numbered 1 through N, and the i-th edge connects Vertex a_i and Vertex b_i. We will construct a new tree T by repeating the following operation on this tree some number of times:

* Add a new vertex to the tree by connecting it to one of the vertices in the current tree with an edge.



Find the minimum possible colorfulness of T. Additionally, print the minimum number of leaves (vertices with degree 1) in a tree T that achieves the minimum colorfulness.

Constraints

* 2 \leq N \leq 100
* 1 \leq a_i,b_i \leq N(1\leq i\leq N-1)
* The given graph is a tree.

Input

Input is given from Standard Input in the following format:


N
a_1 b_1
:
a_{N-1} b_{N-1}


Output

Print two integers with a space in between. First, print the minimum possible colorfulness of a tree T that can be constructed. Second, print the minimum number of leaves in a tree that achieves it.

It can be shown that, under the constraints of this problem, the values that should be printed fit into 64-bit signed integers.

Examples

Input

5
1 2
2 3
3 4
3 5


Output

2 4


Input

8
1 2
2 3
4 3
5 4
6 7
6 8
3 6


Output

3 4


Input

10
1 2
2 3
3 4
4 5
5 6
6 7
3 8
5 9
3 10


Output

4 6


Input

13
5 6
6 4
2 8
4 7
8 9
3 2
10 4
11 10
2 4
13 10
1 8
12 1


Output

4 12
import java.io.*;
import java.util.*;

class Solver {
  private static final int INF = 1 << 20;

  final int n;
  final int[][] abs;
  List<List<Integer>> graph;

  Solver(int n, int[][] abs) {
    this.n = n;
    this.abs = abs;
  }

  private long calculateNumLeaf(List<Integer> centers) {
    Deque<Integer> queue = new ArrayDeque<>();
    Set<Integer> visited = new HashSet<>();
    queue.addAll(centers);
    visited.addAll(centers);
    long numLeaf = centers.size();
    while (!queue.isEmpty()) {
      int maxChildrenSize = 1;
      Deque<Integer> nextQueue = new ArrayDeque<>();
      for (int index : queue) {
        int childrenSize = 0;
        for (int childIndex : graph.get(index)) {
          if (visited.contains(childIndex)) {
            continue;
          }
          visited.add(childIndex);
          nextQueue.add(childIndex);
          childrenSize++;
        }
        maxChildrenSize = Math.max(maxChildrenSize, childrenSize);
      }
      queue = nextQueue;
      numLeaf *= maxChildrenSize;
    }
    return numLeaf;
  }

  public String solve() {
    graph = new ArrayList<>();
    for (int i = 0; i <= n; i++) {
      graph.add(new ArrayList<>());
    }
    for (int[] ab : abs) {
      int a = ab[0];
      int b = ab[1];
      graph.get(a).add(b);
      graph.get(b).add(a);
    }

    int[][] matrix = new int[n + 1][n + 1];
    for (int i = 0; i <= n; i++) {
      for (int j = 0; j <= n; j++) {
        matrix[i][j] = INF;
      }
      matrix[i][i] = 0;
    }
    for (int[] ab : abs) {
      int a = ab[0];
      int b = ab[1];
      matrix[a][b] = 1;
      matrix[b][a] = 1;
    }
    for (int k = 0; k <= n; k++) {
      for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
          matrix[i][j] = Math.min(matrix[i][j], matrix[i][k] + matrix[k][j]);
        }
      }
    }
    List<Integer> centers = null;
    int minMaxDistance = INF;
    for (int i = 1; i <= n; i++) {
      int maxDistance = 0;
      for (int j = 1; j <= n; j++) {
        maxDistance = Math.max(maxDistance, matrix[i][j]);
      }
      if (minMaxDistance > maxDistance) {
        minMaxDistance = maxDistance;
        centers = new ArrayList<>();
        centers.add(i);
      } else if (minMaxDistance == maxDistance) {
        centers.add(i);
      }
    }
    int depth;
    long numLeaf;
    if (centers.size() == 2) {
      depth = minMaxDistance;
      numLeaf = calculateNumLeaf(centers);
    } else {
      int center = centers.get(0);
      depth = minMaxDistance + 1;
      numLeaf = calculateNumLeaf(Arrays.asList(center));
      for (int next : graph.get(centers.get(0))) {
        numLeaf = Math.min(numLeaf, calculateNumLeaf(Arrays.asList(center, next)));
      }
    }

    return String.format("%d %d", depth, numLeaf);
  }
}

public class Main {
  private static void execute(ContestReader reader, ContestWriter out) {
    int n = reader.nextInt();
    int[][] abs = reader.nextInt(n - 1, 2);
    out.println(new Solver(n, abs).solve());
  }
  
  public static void main(String[] args) {
    ContestReader reader = new ContestReader(System.in);
    ContestWriter out = new ContestWriter(System.out);
    execute(reader, out);
    out.flush();
  }
}

class ContestWriter extends PrintWriter {
  ContestWriter(PrintStream printeStream) {
    super(printeStream);
  }

  public void printList(List<? extends Object> list) {
    for (Object object : list) {
      println(object);
    }
  }

  public void printListOneLine(List<? extends Object> list) {
    List<String> stringList = new ArrayList<>();
    for (Object object : list) {
      stringList.add(object.toString());
    }
    println(String.join(" ", stringList));
  }
}

class ContestReader {
  private static final int BUFFER_SIZE = 1024;
  
  private final InputStream stream;
  private final byte[] buffer;
  private int pointer;
  private int bufferLength;
  
  ContestReader(InputStream stream) {
    this.stream = stream;
    this.buffer = new byte[BUFFER_SIZE];
    this.pointer = 0;
    this.bufferLength = 0;
  }
  
  private boolean hasNextByte() {
    if (pointer < bufferLength) {
      return true;
    }
    
    pointer = 0;
    try {
      bufferLength = stream.read(buffer);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    return bufferLength > 0;
  }
  
  private int readByte() {
    if (hasNextByte()) {
      return buffer[pointer++];
    } else {
      return -1;
    }
  }
  
  private static boolean isPrintableChar(int c) {
    return 33 <= c && c <= 126;
  }
  
  public boolean hasNext() {
    while (hasNextByte() && !isPrintableChar(buffer[pointer])) {
      pointer++;
    }
    return hasNextByte();
  }
  
  public String next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    StringBuilder sb = new StringBuilder();
    while(true) {
      int b = readByte();
      if (!isPrintableChar(b)) {
        break;
      }
      sb.appendCodePoint(b);
    }
    return sb.toString();
  }
  
  public String nextLine() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    StringBuilder sb = new StringBuilder();
    while(true) {
      int b = readByte();
      if (!isPrintableChar(b) && b != 0x20) {
        break;
      }
      sb.appendCodePoint(b);
    }
    return sb.toString();
  }
  
  public char nextChar() {
    return next().charAt(0);
  }
  
  public int nextInt() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    
    int n = 0;
    boolean minus = false;
    
    {
      int b = readByte();
      if (b == '-') {
        minus = true;
      } else if ('0' <= b && b <= '9') {
        n = b - '0';
      } else {
        throw new NumberFormatException();
      }
    }
    
    while(true){
      int b = readByte();
      if ('0' <= b && b <= '9') {
        n *= 10;
        n += b - '0';
      } else if (b == -1 || !isPrintableChar(b)) {
        return minus ? -n : n;
      } else {
        throw new NumberFormatException();
      }
    }
  }
  
  public long nextLong() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    
    long n = 0;
    boolean minus = false;
    
    {
      int b = readByte();
      if (b == '-') {
        minus = true;
      } else if ('0' <= b && b <= '9') {
        n = b - '0';
      } else {
        throw new NumberFormatException();
      }
    }
    
    while(true){
      int b = readByte();
      if ('0' <= b && b <= '9') {
        n *= 10;
        n += b - '0';
      } else if (b == -1 || !isPrintableChar(b)) {
        return minus ? -n : n;
      } else {
        throw new NumberFormatException();
      }
    }
  }
  
  public double nextDouble() {
    return Double.parseDouble(next());
  }
  
  public String[] next(int n) {
    String[] array = new String[n];
    for (int i = 0; i < n; i++) {
      array[i] = next();
    }
    return array;
  }
  
  public String[] nextLine(int n) {
    String[] array = new String[n];
    for (int i = 0; i < n; i++) {
      array[i] = nextLine();
    }
    return array;
  }
  
  public char[] nextChar(int n) {
    char[] array = new char[n];
    for (int i = 0; i < n; i++) {
      array[i] = nextChar();
    }
    return array;
  }
  
  public int[] nextInt(int n) {
    int[] array = new int[n];
    for (int i = 0; i < n; i++) {
      array[i] = nextInt();
    }
    return array;
  }
  
  public long[] nextLong(int n) {
    long[] array = new long[n];
    for (int i = 0; i < n; i++) {
      array[i] = nextLong();
    }
    return array;
  }
  
  public double[] nextDouble(int n) {
    double[] array = new double[n];
    for (int i = 0; i < n; i++) {
      array[i] = nextDouble();
    }
    return array;
  }
  
  public char[] nextCharArray() {
    return next().toCharArray();
  }
  
  public String[][] next(int n, int m) {
    String[][] matrix = new String[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = next();
      }
    }
    return matrix;
  }
  
  public int[][] nextInt(int n, int m) {
    int[][] matrix = new int[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = nextInt();
      }
    }
    return matrix;
  }
  
  public char[][] nextChar(int n, int m) {
    char[][] matrix = new char[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = nextChar();
      }
    }
    return matrix;
  }
  
  public long[][] nextLong(int n, int m) {
    long[][] matrix = new long[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = nextLong();
      }
    }
    return matrix;
  }
  
  public double[][] nextDouble(int n, int m) {
    double[][] matrix = new double[n][m];
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < m; j++) {
        matrix[i][j] = nextDouble();
      }
    }
    return matrix;
  }
  
  public char[][] nextCharArray(int n) {
    char[][] matrix = new char[n][];
    for (int i = 0; i < n; i++) {
      matrix[i] = next().toCharArray();
    }
    return matrix;
  }
}
