HDU6446(树上、排列的贡献计算)
关键点在于:全排列中,任意两点u、v相邻的次数一定是(n - 1)! * 2次,即一个常数(可以由高中数学知识计算,将这两个点捏一起然后全排列然后乘二;或者用n! / C(2, n))。
这之后就好算了,每条边算一下子树size对吧,乘法原理就是贡献次数,乘以边权加一起就行了。
所以不是dfs就行了吗,跟dp有啥关系……
PS:变量名起的不行,不该叫inv,而是fac,代表阶乘
1 const int maxn = 1e5 + 5; 2 const int mod = 1e9 + 7; 3 int n, tot; 4 int size[maxn]; 5 struct Edge { 6 int to, nxt; 7 ll cost; 8 }e[maxn << 1]; 9 int head[maxn]; 10 ll inv[maxn], f[maxn], ans; 11 12 inline void add(int u, int v, ll cost) { 13 e[++tot].to = v, e[tot].cost = cost, e[tot].nxt = head[u], head[u] = tot; 14 } 15 16 inline void dfs(int cur, int fa) { 17 size[cur] = 1; 18 for (int i = head[cur]; i; i = e[i].nxt) { 19 int son = e[i].to; 20 if (son == fa) continue; 21 f[son] = e[i].cost; 22 dfs(son, cur); 23 size[cur] += size[son]; 24 } 25 if (fa) ans = (ans + (ll)(n - size[cur]) * size[cur] % mod * f[cur] % mod) % mod; 26 } 27 28 int main() { 29 inv[0] = 1; 30 rep(i, 1, maxn - 5) inv[i] = inv[i - 1] * i % mod; 31 32 while (~scanf("%d", &n)) { 33 ans = tot = 0; 34 rep(i, 1, n) head[i] = 0; 35 36 rep(i, 1, n - 1) { 37 int u, v; 38 ll cost; 39 read(u), read(v), read(cost); 40 add(u, v, cost), add(v, u, cost); 41 } 42 43 dfs(1, 0); 44 writeln(ans * inv[n - 1] % mod * 2 % mod); 45 } 46 return 0; 47 }