There are NN vertices connected by N−1N−1 edges, each edge has its own length.
The set { 1,2,3,…,N1,2,3,…,N } contains a total of N!N! unique permutations, let’s say the ii-th permutation is PiPi and Pi,jPi,j is its jj-th number.
For the ii-th permutation, it can be a traverse sequence of the tree with NNvertices, which means we can go from the Pi,1Pi,1-th vertex to the Pi,2Pi,2-th vertex by the shortest path, then go to the Pi,3Pi,3-th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,NPi,N-th vertex, let’s define the total distance of this route as D(Pi)D(Pi) , so please calculate the sum of D(Pi)D(Pi) for all N!N!permutations.
Input
There are 10 test cases at most.
The first line of each test case contains one integer NN ( 1≤N≤1051≤N≤105 ) .
For the next N−1N−1 lines, each line contains three integer XX, YY and LL, which means there is an edge between XX-th vertex and YY-th of length LL ( 1≤X,Y≤N,1≤L≤1091≤X,Y≤N,1≤L≤109 ) .
Output
For each test case, print the answer module 109+7109+7 in one line.
Sample Input
3 1 2 1 2 3 1 3 1 2 1 1 3 2
Sample Output
16 24
n个点,给出n-1条线(不会构成环)及其权值,求以这n个点的全排列为路径的权值之和
假设xy=a,而在n个点的全排列中,x点和y点相邻的情况出现的次数是2*(n-1)*(n-2)!
(2:xy=yx;n-1:xy在n个点中有n-1种位置可放;(n-2)!:放好xy之后,剩下的n-2个数任意放,即A n-2 取 n-2)
所以问题变为所有点对的距离*权值*次数之和
因为所有点对次数是一样的,所以关键在于求出所有点对的距离*权值之和
队友超级机智,相处了一个好办法,假设题目给了xy的长度,因为不可能出现环,所以路径是唯一的
ac的距离必定包含xy,也就是说可以算出经过每一段的次数*权值
对于线段xy,左边有a、x、b三个点,右边有y、c两个点,所以经过线段xy的次数肯定是2*3=6次,而且若已知一边的点数w,另一边的点数也是知道的(n-w)
如果把图建成一棵树,对于每一条枝干(线段),线段指向的父节点及其子节点总和就相当于线段一边的所有点数
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<fstream>
#include<math.h>
#include<stack>
#include<queue>
#include<bitset>
#include<utility>
#include<set>
#include<map>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const double eps=0.0000000000001;
const ll mod=1000000007;
int t;
int n;
struct P{
int x;
int y;
ll v;
int nt;
};
P e[100005];
int head[100005];
int w[100005];
bool f[100005];
ll jc(int n){
//计算阶乘
ll ans=1;
while(n>=1){
ans*=n;
ans%=mod;
n--;
}
return ans;
}
ll gt(int s){
//深搜遍历整棵树,得到每个顶点子节点+1(自己)的数量
if(head[s]==-1){
w[s]=1;
return w[s];
}
ll ww=0;
for(int i=head[s];i!=-1;i=e[i].nt){
ww+=gt(e[i].y);
}
ww++;
w[s]=ww;
return ww;
}
void add_e(int i,int x,int y,ll v){
e[i].x=x;
e[i].y=y;
e[i].v=v;
e[i].nt=head[x];
head[x]=i;
}
int main(){
while(~scanf("%d",&n)){
memset(head,-1,sizeof(head));
memset(f,0,sizeof(f));
int x,y;
ll v;
for(int i=0;i<n-1;i++){
scanf("%d%d%Illd",&x,&y,&v);
if(f[y]==0){
add_e(i,x,y,v);
f[y]=1;
}
else{
add_e(i,y,x,v);
f[x]=1;
}
//使图成为一棵树,如果已经有点指向y点了,就反向插入边
}
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++){
if(f[i]==0){
gt(i);
break;
}//找到根节点求出w
}
/*
for(int i=1;i<=n;i++){
cout<<i<<" "<<w[i]<<endl;
}
*/
ll ans=0;
for(int i=0;i<n-1;i++){
ll sum=0;
sum=(ll)w[e[i].y]*(n-w[e[i].y]);
sum%=mod;
//经过边i的次数
sum*=e[i].v;sum%=mod;
//边i对答案贡献的价值量
ans+=sum;ans%=mod;
//所有边累加
}
ans*=jc(n-2); ans%=mod;
ans*=2; ans%=mod;
ans*=(n-1); ans%=mod;
printf("%lld\n",ans);
}
return 0;
}
这道题没做出来真的好不甘心啊!o(╥﹏╥)o
已经把基本思路都想出来了,可是没有考虑到建图的时候要建成树,想出思路的时候很兴奋直接就开始打,没有先把所有环节理清楚,想着边打边顺,但是图论的题真的会越改越懵,还是改不了急躁,感觉坑了一波队友 (>人<)
感觉现在已经是什么时候放弃都不奇怪的状态了,但是至少挣扎到博客文章数破80 (ノへ ̄、)