題意:
有 n 個點標爲 1 ... n,對其全排列,按排列後順序走,求其路徑總和。
題解:
通過對樣例全排列發現答案就是邊的使用次數乘上權值的求和。
如果我們考慮一個邊,除去這個邊的兩點,對其 n-1 個點全排列(把邊想象成一個點),正反 2 次,所以就有 (n-1)!*2 的方法數,再乘上權值和邊的兩邊數量。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <stack>
#include <cmath>
#include <deque>
#include <queue>
#include <list>
#include <set>
#include <map>
#define mem(a, b) memset(a, b, sizeof(a))
#define inf 0x7ffffff
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 1e5+5, mod = 1e9+7;
vector<int> mapp[maxn];
int p[maxn], have[maxn], n;
struct Edge{
int u, v;
ll len;
}edge[maxn];
void dfs(int now, int last){
have[now]++;
for(int i = 0; i < mapp[now].size(); i++){
int v = mapp[now][i];
if(v != last){
dfs(v, now);
have[now] += have[v];
p[v] = now;
}
}
}
ll power[maxn];
void init(){
mem(have, 0);
for(int i = 1; i <= n; i++){
mapp[i].clear();
}
}
int main(){
power[0] = 1;
for(ll i = 1; i < maxn; i++){
power[i] = power[i-1]*i % mod;
}
while(~scanf("%d", &n)){
init();
for(int i = 1; i < n; i++){
scanf("%d %d %lld", &edge[i].u, &edge[i].v, &edge[i].len);
mapp[edge[i].u].push_back(edge[i].v);
mapp[edge[i].v].push_back(edge[i].u);
}
dfs(1, 0);
ll ans = 0;
for(int i = 1; i < n; i++){
if(p[edge[i].u] == edge[i].v){
ans = (ans + power[n-1] * have[edge[i].u] % mod * (n - have[edge[i].u]) % mod * edge[i].len % mod) % mod;
}
else{
ans = (ans + power[n-1] * have[edge[i].v] % mod * (n - have[edge[i].v]) % mod * edge[i].len % mod) % mod;
}
}
printf("%lld\n", ans*2 % mod);
}
}