HDU-6446-Tree and Permutation(全排列的规律+树状DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6446

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

题目大意:给出一个n,然后是n-1条路,对于每条路,输入,u->v  权值w;

最后给出全排列的1-n的所有长度之和,

样例:

这样的一颗树,然后输出,1-2-3,1-3-2,2-1-3,2-3-1,3-1-2,3-2-1,总共六种路径的长度之和;

分别为:

1->2->3=1->2+2->3=1+1=2   

1->3->2 =1->2->3+2->3=2+1=3       

2->1->3=2->1+1->2->3=1+2=3 

 .......

把他们都加起来即可;

因为是全排列,所以每两点之间出现的次数是相等的,例:

n=3时,有:

1,2,3     1,3,2

2,1,3     2,3,1

3,1,2     3,2,1

发现每两个点之间出现的次数时相等的,所以答案就是 点之间的重复次数 * 所有点到点之间的长度之和(1-2,1-3,2-3)

运用DFS树求出所有点到点之间的长度之和。

对于重复次数 ,可以打表找规律(大概打个10来项,然后找规律),也可以手推;

最后是F[i]=F[i-1]*(i-1);

然后输出答案即可

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
//#define mod 1e9+7
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);

const int MAXN=1e5+5;
const ll mod=1e9+7;

struct node{
	int v,w;
	ll nxt;
	node(int _v=0,int _w=0,ll _nxt=0):
	v(_v),w(_w),nxt(_nxt){}
}edge[MAXN<<1];
int head[MAXN],e;
ll sum,num[MAXN];
int n;

void intt()
{
	clean(num,-1);
	clean(head,-1);
	e=0;
	sum=0;
}

void add(int u,int v,ll w)
{
	edge[e]=node(v,w,head[u]);
	head[u]=e++;
}

void dfs(ll u,ll fa)
{
	printf("%d %d\n",u,fa);
	num[u]=1;
	for(int i=head[u];i+1;i=edge[i].nxt)
	{
		int v=edge[i].v;
		ll w=edge[i].w;
		printf("%d %d\n%d %d %d\n",i,edge[i].nxt,u,v,fa);
		if(v!=fa)//由于是无向图,因此我们要防止它向上回溯
		{
			dfs(v,u);
			num[u]+=num[v];
			sum=(sum+(num[v]*((n-num[v])*w)%mod)%mod)%mod;
		}
	}
}

ll ans[MAXN];

void init()
{
	ans[2]=2;
	ans[3]=4;
	for(int i=4;i<MAXN;++i)
		ans[i]=(ans[i-1]*(i-1))%mod;
}

int main()
{
	init();
	while(scanf("%d",&n)!=EOF)
	{
		intt();
		int a,b;
		ll l;
		for(int i=0;i<n-1;++i)
		{
			scanf("%d%d%lld",&a,&b,&l);
			add(a,b,l);
			add(b,a,l);
		}
		dfs(1,-1);
		printf("%lld\n",(sum*ans[n])%mod);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/82110471