Tree and Permutation
给出一个1,2,3...N的排列,显然全部共有N!种排列,每种排列的数字代表树上的一个结点,设Pi是其中第i种排列的相邻数字表示的结点的距离之和,让我们求sum(Pi)(1<=i<=N!)。
可以设dis(i, j)为树上任意两点间的最短距离,每两点之间的距离都出现了 (N-1)!次,所求答案为 (N-1)! * sum(dis(i, j))。
由于这是一棵树,dis(i, j)的最短路径是唯一的(不存在环),那么对于相邻结点u, v,可以发现边(u, v)走过的次数为左边结点数量*右边结点数量。
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 100010; const int mod = 1e9+7; typedef long long ll; typedef pair<int, int> P; vector<P> G[maxn]; ll fact[maxn], ans; int n, child[maxn]; void dfs(int u, int fa)///记录下父节点,避免重复遍历父节点 { // printf("%d->%d ", fa, u); child[u] = 1; int len = G[u].size(); for(int i=0;i<len;i++) { int v = G[u][i].first; if(v!=fa) { dfs(v, u); child[u] += child[v]; ans += child[v]*(n-child[v])*G[u][i].second % mod; ans %= mod; } } } signed main() { fact[0] = 1; for(int i=1;i<maxn;i++) { fact[i] = fact[i-1] * i % mod; // printf("%d %lld ", i, fact[i]); } int u, v, d; while(scanf("%d", &n)!=EOF) { memset(child, 0, sizeof(child)); for(int i=1;i<n;i++) { scanf("%d %d %d", &u, &v, &d); G[u].push_back(P(v, d)); G[v].push_back(P(u, d)); } ans = 0; dfs(1, -1); printf("%lld ", 2*ans*fact[n-1]%mod); for(int i=1;i<=n;i++) G[i].clear(); } return 0; }