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 }

 

posted @ 2019-04-03 00:07  AlphaWA  阅读(211)  评论(0编辑  收藏  举报