题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6446
题目大意:给一棵N个节点N-1条边的树,把1~N的全排列的最短路径求和,也就是比如N=3的话,路径排列就有【1-2-3】,【1-3-2】,【2-1-3】,【2-3-1】,【3-1-2】,【3-2-1】这N!种。比赛的时候打了个表发现规律就是每条边会出现2*(N-1)!次,所以计算出树上任意两点间的距离和再乘上2*(N-1)!就可以了,搜这个找到了个HDU 2376是类似做法,然而有的地方没转换成LL所以WA了好几发。。还是罗大佬他们队直接改了下我的代码过了。。基本代码是一样的没什么变动,注意MOD和LL就好了。
/*
* @Author: SamsonHo
* @Date: 2018-09-11-08.36.01
* @URL:
*/
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MOD = 1e9+7;
int n;
LL sum[MAXN],dp[MAXN];
vector<pair<int,int> > e[MAXN];
void dfs(int cur,int father)
{
sum[cur] = 1;
int len = e[cur].size();
for(int i = 0; i < len; ++i)
{
int v = e[cur][i].first;
if(v == father) continue;
dfs(v,cur);
sum[cur] = (sum[cur]+sum[v])%MOD;
dp[cur] = (dp[cur] + (dp[v]*1LL + 1LL*(sum[v]*(n-sum[v])*e[cur][i].second%MOD)))%MOD;
}
}
int main(void)
{
while(~scanf("%d",&n))
{
for(int i = 0; i <= n; ++i)
e[i].clear();
memset(sum,0,sizeof sum);
memset(dp,0,sizeof dp);
int x,y,l;
for(int i = 0; i < n-1; ++i)
{
scanf("%d%d%d",&x,&y,&l);
e[x].push_back(make_pair(y,l));
e[y].push_back(make_pair(x,l));
}
dfs(1,0);
LL tmp = 1;
for(int i = 1; i <= n-1; ++i)
tmp = tmp*i%MOD;
tmp = tmp*2%MOD;
printf("%lld\n",dp[1]*tmp%MOD);
}
}