HDU 6446 I. Tree and Permutation

链接

http://acm.hdu.edu.cn/showproblem.php?pid=6446

题意

$n$ 个点的树形图,按照排列遍历树,求 $n!$ 个排列的总路径长。

思路

对于每条路径 $i\rightarrow j$,在所有排列中出现的总次数是 $(n-1)*(n-2)!$,

DFS 遍历所有边,每条边 $(u,v)$ 存在于 $size(v)*(n-size(v))$ 条路径中,

所以每条无向边对答案的贡献是 $2*(n-1)*(n-2)!size(v)(n-size(v))$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <bits/stdc++.h>
#define int long long
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const int N=1e5+5;
const int MOD=1e9+7;
int n,sz[N],fac[N],res;
VPII g[N];
void dfs(int u,int fa) {
sz[u]=1;
for(auto x:g[u]) {
int v=x.FI,w=x.SE;
if(v==fa) continue;
dfs(v,u);
sz[u]+=sz[v];
res=(res+sz[v]*(n-sz[v])%MOD*w%MOD)%MOD;
}
}
signed main() {
//freopen("D:/Sublime Text 3/in.txt","r",stdin);
fac[0]=1;
for(int i=1;i<=100000;i++) fac[i]=fac[i-1]*i%MOD;
while(~scanf("%lld",&n)) {
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<n;i++) {
int u,v,w;
scanf("%lld%lld%lld",&u,&v,&w);
g[u].EB(v,w);
g[v].EB(u,w);
}
res=0;
dfs(1,0);
printf("%lld\n",res*fac[n-1]%MOD*2%MOD);
}
return 0;
}