Problem:
Score : 1800 points

Problem Statement

There is a tree T with N vertices, numbered 1 through N.
For each 1 ≤ i ≤ N - 1, the i-th edge connects vertices a_i and b_i.

Snuke is constructing a directed graph T' by arbitrarily assigning direction to each edge in T. (There are 2^{N - 1} different ways to construct T'.)

For a fixed T', we will define d(s,\ t) for each 1 ≤ s,\ t ≤ N, as follows:

d(s,\ t) = (The number of edges that must be traversed against the assigned direction when traveling from vertex s to vertex t)

In particular, d(s,\ s) = 0 for each 1 ≤ s ≤ N.
Also note that, in general, d(s,\ t) ≠ d(t,\ s).

We will further define D as the following:

Snuke is constructing T' so that D will be the minimum possible value.
How many different ways are there to construct T' so that D will be the minimum possible value, modulo 10^9 + 7?

Constraints

2 ≤ N ≤ 1000

1 ≤ a_i,\ b_i ≤ N

The given graph is a tree.

Input

The input is given from Standard Input in the following format:

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

Output

Print the number of the different ways to construct T' so that D will be the minimum possible value, modulo 10^9 + 7.

Sample Input 1

4
1 2
1 3
1 4

Sample Output 1

2

The minimum possible value for D is 1.
There are two ways to construct T' to achieve this value, as shown in the following figure:

Sample Input 2

4
1 2
2 3
3 4

Sample Output 2

6

The minimum possible value for D is 2.
There are six ways to construct T' to achieve this value, as shown in the following figure:

Sample Input 3

6
1 2
1 3
1 4
2 5
2 6

Sample Output 3

14

Sample Input 4

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

Sample Output 4

102

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

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

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
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);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        static final long MODULO = (long) (1e9 + 7);

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt();
            TaskD.Vertex[] vs = new TaskD.Vertex[n];
            for (int i = 0; i < n; ++i) {
                vs[i] = new TaskD.Vertex();
            }
            for (int i = 0; i < n - 1; ++i) {
                TaskD.Vertex a = vs[in.nextInt() - 1];
                TaskD.Vertex b = vs[in.nextInt() - 1];
                a.adj.add(b);
                b.adj.add(a);
            }

            List<TaskD.Vertex> leaves = new ArrayList<>();
            for (TaskD.Vertex v : vs) {
                v.deg = v.adj.size();
                if (v.deg == 1) {
                    leaves.add(v);
                }
            }
            int remains = n;
            int diameter = 0;
            while (remains > 2) {
                diameter += 2;
                if (leaves.size() == remains) throw new RuntimeException();
                remains -= leaves.size();
                List<TaskD.Vertex> newLeaves = new ArrayList<>();
                for (TaskD.Vertex v : leaves) {
                    for (TaskD.Vertex u : v.adj) {
                        --u.deg;
                        if (u.deg == 1) {
                            newLeaves.add(u);
                        }
                    }
                }
                leaves = newLeaves;
            }
            if (remains != leaves.size()) throw new RuntimeException();
            diameter += remains - 1;
            int allowed = (diameter + 1) / 2;
            if (remains == 1) {
                TaskD.Vertex a = leaves.get(0);
                for (TaskD.Vertex u : a.adj) {
                    u.solve(a, allowed, true);
                }
                long res = 0;
                for (int maxDown = 0; maxDown <= allowed; ++maxDown) {
                    long p = 1;
                    for (TaskD.Vertex u : a.adj) {
                        p = p * u.res[maxDown] % MODULO;
                    }
                    res = (res + p) % MODULO;
                }
                out.println(res);
            } else if (remains == 2) {
                TaskD.Vertex a = leaves.get(0);
                TaskD.Vertex b = leaves.get(1);
                long res = 0;
                a.solve(b, allowed + 1, false);
                int[] ap1 = a.res;
                a.solve(b, allowed, false);
                int[] ap0 = a.res;
                b.solve(a, allowed + 1, false);
                int[] bp1 = b.res;
                b.solve(a, allowed, false);
                int[] bp0 = b.res;
                for (int maxDown = 0; maxDown < allowed; ++maxDown) {
                    res = (res + ap0[maxDown] * (long) bp0[maxDown]) % MODULO;
                }
                for (int maxDown = 0; maxDown < allowed; ++maxDown) {
                    res = (res + 2 * ap0[maxDown] * (long) (bp1[maxDown] - bp0[maxDown])) % MODULO;
                }
                for (int maxDown = 0; maxDown < allowed; ++maxDown) {
                    res = (res + 2 * bp0[maxDown] * (long) (ap1[maxDown] - ap0[maxDown])) % MODULO;
                }
                res = (res + MODULO) % MODULO;
                out.println(res);
            } else throw new RuntimeException();
        }

        static class Vertex {
            List<TaskD.Vertex> adj = new ArrayList<>();
            int deg;
            int[] res;

            public void solve(TaskD.Vertex parent, int allowed, boolean extraEdge) {
                int[] children = new int[allowed];
                Arrays.fill(children, 1);
                for (TaskD.Vertex u : adj)
                    if (u != parent) {
                        u.solve(this, allowed - 1, true);
                        for (int cnt = 0; cnt < allowed; ++cnt) {
                            children[cnt] = (int) (children[cnt] * (long) u.res[cnt] % MODULO);
                        }
                    }
                if (extraEdge) {
                    res = new int[allowed + 1];
                    for (int i = 0; i < allowed; ++i) {
                        res[i] = (int) ((res[i] + children[i]) % MODULO);
                        res[i + 1] = (int) ((res[i + 1] + children[i]) % MODULO);
                    }
                } else {
                    res = children;
                }
            }

        }

    }

    static 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());
        }

    }
}