hdu6446(树形dp+公式推导)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yu121380/article/details/82226015

Tree and Permutation

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1414    Accepted Submission(s): 528

Problem Description

There are N vertices connected by N−1 edges, each edge has its own length.
The set { 1,2,3,…,N } contains a total of N! unique permutations, let’s say the i-th permutation is Pi and Pi,j is its j-th number.
For the i-th permutation, it can be a traverse sequence of the tree with N vertices, which means we can go from the Pi,1-th vertex to the Pi,2-th vertex by the shortest path, then go to the Pi,3-th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,N-th vertex, let’s define the total distance of this route as D(Pi) , so please calculate the sum of D(Pi) for all N! permutations.

Input

There are 10 test cases at most.
The first line of each test case contains one integer N ( 1≤N≤105 ) .
For the next N−1 lines, each line contains three integer X, Y and L, which means there is an edge between X-th vertex and Y-th of length L ( 1≤X,Y≤N,1≤L≤109 ) .

Output

For each test case, print the answer module 109+7 in one line.

Sample Input

3

1 2 1

2 3 1

3

1 2 1

1 3 2

Sample Output

16

24

Source

2018中国大学生程序设计竞赛 - 网络选拔赛

解析:考虑u,v两个点路径对答案的贡献次数,因为是全排列,那么u,v可以放在1,2位置,2.3位置。。。有(n-1)个位置,在颠倒一下顺序就是(n-1)*2,然后其他n-2个点可以随意排,也就是(n-2)!,所以任意一条边的贡献次数就是2*(n-1)!

所以问题就变为求任意两点的路径和,在这个问题上每条边的贡献就是用这条把树节点分为两个部分,那么这个边的贡献次数就是这两部分点的乘积了,这个用dfs求树大小就可以了。dp[i]表示第i到n点总边的贡献次数,i表示第几个点,比如一条边的两端节点数x+y=n,dp[i]+=dp[(i的邻点)]+x*(n-x)*w,则ans=dp[1]*2*(n-1)!

#include<bits/stdc++.h>
using namespace std;
 
#define e exp(1)
#define pi acos(-1)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define mem(a,b) memset(a,b,sizeof(a))
int gcd(int a,int b){return b?gcd(b,a%b):a;}

const int maxn=1e5+5;
struct node{
	int v,w;
};
ll f[maxn],dp[maxn],sum[maxn];
int n;
vector<node> ve[maxn];

void dfs(int x,int f)
{
	sum[x]=1;
	for(int i=0; i<ve[x].size(); i++)
	{
		int a=ve[x][i].v;
		int b=ve[x][i].w;
		if(a==f)continue;
		dfs(a,x);
		sum[x]+=sum[a];
		dp[x]=(dp[x]+dp[a]+b*sum[a]%mod*(n-sum[a])%mod)%mod;
	}
}
int main()
{
	f[0]=1;
	for(int i=1; i<maxn; i++)f[i]=f[i-1]*i%mod;
	while(~scanf("%d",&n))
	{
		for(int i=1; i<=n; i++)ve[i].clear();
		mem(dp,0);
		mem(sum,0);
		
		
		for(int i=1; i<n; i++)
		{
			int x,y,vv;scanf("%d%d%d",&x,&y,&vv);
			node a,b;
			a.v=y,a.w=vv;
			ve[x].push_back(a);
			b.v=x,b.w=vv;
			ve[y].push_back(b);
		}
		dfs(1,-1);
		//printf("%lld***\n",dp[1]);
		ll ans=(dp[1]*f[n-1]%mod*2)%mod;
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/yu121380/article/details/82226015