1. 程式人生 > >HDU 6446 Tree and Permutation(根節點)

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;
}