Problem:
Score : 800 points

Problem Statement

There is a tree with N vertices. The vertices are numbered 1 through N. The i-th edge (1 \leq i \leq N - 1) connects Vertex x_i and y_i. For vertices v and w (1 \leq v, w \leq N), we will define the distance between v and w d(v, w) as "the number of edges contained in the path v-w".

A squirrel lives in each vertex of the tree. They are planning to move, as follows. First, they will freely choose a permutation of (1, 2, ..., N), p = (p_1, p_2, ..., p_N). Then, for each 1 \leq i \leq N, the squirrel that lived in Vertex i will move to Vertex p_i.

Since they like long travels, they have decided to maximize the total distance they traveled during the process. That is, they will choose p so that d(1, p_1) + d(2, p_2) + ... + d(N, p_N) will be maximized. How many such ways are there to choose p, modulo 10^9 + 7?

Constraints

2 \leq N \leq 5,000

1 \leq x_i, y_i \leq N

The input graph is a tree.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_{N - 1} y_{N - 1}

Output

Print the number of the ways to choose p so that the condition is satisfied, modulo 10^9 + 7.

Sample Input 1

3
1 2
2 3

Sample Output 1

3

The maximum possible distance traveled by squirrels is 4.
There are three choices of p that achieve it, as follows:

(2, 3, 1)

(3, 1, 2)

(3, 2, 1)

Sample Input 2

4
1 2
1 3
1 4

Sample Output 2

11

The maximum possible distance traveled by squirrels is 6.
For example, p = (2, 1, 4, 3) achieves it.

Sample Input 3

6
1 2
1 3
1 4
2 5
2 6

Sample Output 3

36

Sample Input 4

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

Sample Output 4

396

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

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

struct Centroid{
  Int n;
  vector<Int> sz,centroid,used;
  vector<vector<Int> > G;
  Centroid(){}
  Centroid(Int n):n(n),sz(n,1),used(n,0),G(n){}

  void add_edge(Int u,Int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void input(Int offset=0){
    for(Int i=1;i<n;i++){
      Int u,v;
      cin>>u>>v;
      add_edge(u+offset,v+offset);
    }
  }
  
  void dfs(Int v,Int p) {
    Int ok=1;
    for (Int u:G[v]){
      if(u==p||used[u]) continue;
      dfs(u,v);
      sz[v]+=sz[u];
      ok&=(sz[u]<=n/2);
    }
    ok&=(n-sz[v]<=n/2);
    if(ok) centroid.push_back(v);
  };
  
  vector<Int> build(Int r=0) {
    n=0;
    auto bfs=[&](Int k){      
      queue<Int> q;
      sz[r]=k;
      q.emplace(r);
      while(!q.empty()){
	Int v=q.front();q.pop();
	n+=k;
	for(Int u:G[v]){
	  if(sz[u]==k||used[u]) continue;
	  sz[u]=k;
	  q.emplace(u);
	}
      }
    };
    bfs(0);bfs(1);
    centroid.clear();
    dfs(r,-1);
    return centroid;
  }

  void disable(Int v){
    used[v]=1;
  }

  void enable(Int v){
    used[v]=0;
  }
};


#define MOD 1000000007
#define MAX_P 200005
Int fact[MAX_P],inv[MAX_P],finv[MAX_P];;
Int extgcd(Int a,Int b,Int& x,Int& y){
  Int d=a;
  if(b!=0){
    d=extgcd(b,a%b,y,x);
    y-=(a/b)*x;
  }else{
    x=1;y=0;
  }
  return d;
}
Int mod_inverse(Int a,Int mod){
  Int x,y;
  extgcd(a,mod,x,y);
  return (mod+x%mod)%mod;
}

Int mod_pow(Int x,Int n,Int mod){
  Int res=1;
  while(n){
    if(n&1) (res*=x)%=mod;
    (x*=x)%=mod;
    n>>=1;
  }
  return res;
}

Int mod_inverse2(Int a,Int mod){
  return mod_pow(a,mod-2,mod);
}

void init(Int mod){
  fact[0]=1;
  for(Int i=1;i<MAX_P;i++)
    fact[i]=(fact[i-1]*i)%mod;

  inv[1]=1;
  for(Int i=2;i<MAX_P;i++)
    inv[i]=inv[mod%i]*(mod-mod/i)%mod;
  
  finv[0]=1;
  for(Int i=1;i<MAX_P;i++)
    finv[i]=finv[i-1]*inv[i]%mod;
}

Int mod_fact(Int n,Int mod,Int& e){
  e=0;
  if(n==0) return 1;
  Int res=mod_fact(n/mod,mod,e);
  e+=n/mod;
  if(n/mod%2!=0)return res*(mod-fact[n%mod]) %mod;
  return res*fact[n%mod]%mod;
}

Int mod_comb(Int n,Int k,Int mod){
  if(n==k||k==0) return 1;
  Int e1,e2,e3;
  Int a1=mod_fact(n,mod,e1),a2=mod_fact(k,mod,e2),a3=mod_fact(n-k,mod,e3);
  if(e1>e2+e3) return 0;
  return a1*mod_inverse(a2*a3%mod,mod)%mod;
}

Int mod_comb2(Int n,Int k,Int mod){
  Int res=1;
  for(Int i=0;i<k;i++){
    res*=(n-i)%mod;
    res%=mod;
    res*=mod_inverse(i+1,mod);
    res%=mod;
  }
  return res;
}

//only for prime mod
Int mod_comb3(Int n,Int k,Int mod){
  if(k<0||k>n) return 0;
  return fact[n]*finv[k]%mod*finv[n-k]%mod;
}

Int montmort(Int n,Int mod){
  Int res=0,inv=1;
  for(Int k=2;k<=n;k++){
    (inv*=mod_inverse(k,mod))%=mod;
    if(k%2) (res+=mod-inv)%=mod;
    else (res+=inv)%=mod;
  }
  for(Int i=1;i<=n;i++)
    (res*=i)%=mod;
  return res;
}

// calculate P(t) from given points in [0,N]
Int LagrangePolynomial(vector<Int> &y,Int t,const Int mod){
  init(mod);
  Int n=y.size()-1;
  Int num=1;
  for(Int i=0;i<=n;i++)
    num=num*((t-i)%mod)%mod;
  Int res=0;
  for(Int i=0;i<=n;i++){
    Int tmp=(y[i]*num%mod)*mod_inverse((t-i)%mod,mod)%mod;
    tmp=tmp*finv[i]%mod;
    tmp=tmp*finv[n-i]%mod;
    if((n-i)&1) tmp=mod-tmp;
    res=(res+tmp)%mod;
  }
  return res;
}

//INSERT ABOVE HERE
signed main(){
  Int n;
  cin>>n;
  Centroid G(n);
  G.input(-1);
  vector<Int> cs=G.build();
  init(MOD);
  if(cs.size()%2==0){
    Int ans=fact[n/2]*fact[n/2]%MOD;
    cout<<ans<<endl;
    return 0;
  }
  vector<Int> v;
  Int r=cs[0];
  G.build(r);
  for(Int u:G.G[r]) v.emplace_back(G.sz[u]);
  
  vector<Int> dp(n+1,0);
  dp[0]=1;
  for(Int i=0;i<(Int)v.size();i++){
    vector<Int> nx(n+1,0);
    for(Int k=0;k<=v[i];k++){
      Int res=mod_comb3(v[i],k,MOD)*fact[v[i]]%MOD;
      res=res*finv[v[i]-k]%MOD;
      for(Int j=0;k+j<=n;j++){
	nx[k+j]+=dp[j]*res%MOD;
	nx[k+j]%=MOD;
      }
    }
    swap(dp,nx);
  }
  for(Int i=0;i<=n;i++){
    //cout<<i<<":"<<dp[i]<<" "<<fact[n-i]<<endl;
    dp[i]*=fact[n-i]%MOD;
    dp[i]%=MOD;
  }
  
  Int ans=0;
  for(Int i=0;i<=n;i++){
    if(i&1) ans+=MOD-dp[i];
    else ans+=dp[i];
    ans%=MOD;
  }
  cout<<ans<<endl;
  return 0;
}