HDU 6446 Tree and Permutation(dfs+思维)
解析:
对于树上的一条边,设其两端的点数为 x,y,边长为 L. 对于一个排列,总共会行动 n−1 次,一次行动如果要经过这一条边,那么这次行动的起点和终点一定要在这条边的不同的两端,对应的排列数为 xy(n−2)! . 由于边长为 L, 有 n−1 次行动,还要考虑正反(再乘个 2),所以最终这条边对答案的贡献为2xyL(n−1)! .(大致就是这个结论吧,我也没有太明白。。。)
计算一条边两端的点数用一次 dfs 即可。
#include <bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7f7f7f7f7f
#define mo 1000000007
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=2e5+10;
ll he[N],sz[N],vis[N],ans=0,n,jc[N];
struct node
{
ll v,nex;
ll w;
}ap[N];
ll dfs(int u ){
sz[u]=1; vis[u]=1;
for(int i=he[u];i!=-1;i=ap[i].nex){
int v=ap[i].v;
if(vis[v]) continue;
sz[u]+=dfs(v);
ans=(ans+sz[v]*((ll)n-sz[v])%mo*ap[i].w%mo)%mo;
}
return sz[u];
}
int main()
{
#ifdef local
freopen("D://rush.txt","r",stdin);
#endif
jc[1]=1;
for(ll i=2;i<N;i++)
jc[i]=(jc[i-1]*(i))%mo;
while(scanf("%lld",&n)!=EOF){
memset(he,-1,sizeof he);memset(vis,0,sizeof vis),ans=0;
ll x,y,l,cnt=0;
rep(i,1,n-1){
scanf("%lld%lld%lld",&x,&y,&l);
ap[cnt]={y,he[x],l};he[x]=cnt++;
ap[cnt]={x,he[y],l};he[y]=cnt++;
}
dfs(1);
ans=((ans*jc[n-1]%mo)*2)%mo;
printf("%lld\n",ans);
}
return 0;
}