HDU 6446 Tree and Permutation(根节点)

这道题我记得当时是在网上找的板子。。。。

http://acm.hdu.edu.cn/showproblem.php?pid=6446

先定义一个数n,n个数有n!种排列方法,然后求两条边的权值之和,显然他是有(n-1)!2种结果,对于两个相邻的点来说,他的计算的次数其实是两个边的节点所形成的树的子树的数量。

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int mod  = 1e9+7;
ll son[maxn],s[maxn];
int u,v,w,n;
struct edge{
	int v;
	int w;
};
vector<edge>vec[maxn];
void init(){
	s[1]=1;
	for(int i=2;i<maxn;i++){
		s[i]=s[i-1]*i%mod;
	}
}
ll dfs(int x,int ww,int fat){
	ll ret = 0;
	for(int i=0;i<vec[x].size();i++){
		int t=vec[x][i].v;
		if(t==fat)
		continue;
		ret+=dfs(t,vec[x][i].w,x);
		ret%=mod;
	}
	son[fat]+=son[x]+1;
	ret+=(son[x]+1)*(n-son[x]-1)%mod*ww%mod;
	ret%=mod;
	return ret;
}
int main()
{
	init();
	while(cin>>n){

		memset(son,0,sizeof(son));
		for(int i=0;i<maxn;i++)
			vec[i].clear();
		for(int i=1;i<=n-1;i++){
			scanf("%d%d%d",&u,&v,&w);
			vec[u].push_back(edge{v,w});
			vec[v].push_back(edge{u,w});
		}
		printf("%lld\n",dfs(1,0,0)*s[n-1]*2%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41453511/article/details/84640808