HDU6446 Tree and Permutation
Posted blogggggg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU6446 Tree and Permutation相关的知识,希望对你有一定的参考价值。
题目链接:https://cn.vjudge.net/problem/HDU-6446
知识点: 组合数学
解题思路:
对于树上的一条边,设其两端的点数为 $x, y$,边长为 $L$. 对于一个排列,总共会行动 $n-1$ 次,一次行动如果要经过这一条边,那么这次行动的起点和终点一定要在这条边的不同的两端,对应的排列数为 $xy(n-2)!$ . 由于边长为 $L$, 有 $n-1$ 次行动,还要考虑正反(再乘个 $2$),所以最终这条边对答案的贡献为$2xyL(n-1)!$ .
计算一条边两端的点数用一次 $dfs$ 即可。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MAXN=1e5+5; 5 const LL MOD=1e9+7; 6 vector<int> G[MAXN]; 7 int fa[MAXN]; 8 int have[MAXN]; 9 void dfs(int rt,int last){ 10 have[rt]++; 11 for(int i=0;i<G[rt].size();i++){ 12 int v=G[rt][i]; 13 if(v==last) continue; 14 dfs(v,rt); 15 have[rt]+=have[v]; 16 fa[v]=rt; 17 } 18 } 19 struct Edge{ 20 int u,v; 21 LL val; 22 }e[MAXN]; 23 LL power[MAXN]; 24 void init(){ 25 power[0]=1; 26 for(LL i=1;i<MAXN;i++) 27 power[i]=power[i-1]*i%MOD; 28 } 29 int main(){ 30 init(); 31 int N; 32 while(scanf("%d",&N)==1){ 33 memset(have,0,sizeof(have)); 34 for(int i=1;i<=N;i++) G[i].clear(); 35 for(int i=1;i<N;i++){ 36 scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].val); 37 G[e[i].u].push_back(e[i].v); 38 G[e[i].v].push_back(e[i].u); 39 } 40 dfs(1,0); 41 LL ans=0; 42 for(int i=1;i<N;i++){ 43 if(fa[e[i].u]==e[i].v) 44 ans=(ans+power[N-1]*have[e[i].u]%MOD*(N-have[e[i].u])%MOD*e[i].val%MOD)%MOD; 45 else 46 ans=(ans+power[N-1]*have[e[i].v]%MOD*(N-have[e[i].v])%MOD*e[i].val%MOD)%MOD; 47 } 48 printf("%lld ",ans*2%MOD); 49 } 50 51 return 0; 52 }
以上是关于HDU6446 Tree and Permutation的主要内容,如果未能解决你的问题,请参考以下文章
(1009) HDU 6446 Tree and Permutation(规律+树上各个点的距离和)