2018中国大学生程序设计竞赛 - 网络选拔赛--HDU 6446 Tree and Permutation(思维)

题意:

有 n 个点标为 1 ... n,对其全排列,按排列后顺序走,求其路径总和。

题解:

通过对样例全排列发现答案就是边的使用次数乘上权值的求和。

如果我们考虑一个边,除去这个边的两点,对其 n-1 个点全排列(把边想象成一个点),正反 2 次,所以就有 (n-1)!*2 的方法数,再乘上权值和边的两边数量。

#include <algorithm>
#include  <iostream>
#include   <cstdlib>
#include   <cstring>
#include    <cstdio>
#include    <string>
#include    <vector>
#include    <bitset>
#include     <stack>
#include     <cmath>
#include     <deque>
#include     <queue>
#include      <list>
#include       <set>
#include       <map>
#define mem(a, b) memset(a, b, sizeof(a))
#define inf 0x7ffffff
#define pi acos(-1)
using namespace std;
typedef long long ll;

const int maxn = 1e5+5, mod = 1e9+7;

vector<int> mapp[maxn];
int p[maxn], have[maxn], n;

struct Edge{
	int u, v;
	ll len;
}edge[maxn];

void dfs(int now, int last){
	have[now]++;
	for(int i = 0; i < mapp[now].size(); i++){
		int v = mapp[now][i];
		if(v != last){
			dfs(v, now);
			have[now] += have[v];
			p[v] = now;
		}
	}
}

ll power[maxn];

void init(){
	mem(have, 0);
	for(int i = 1; i <= n; i++){
		mapp[i].clear();
	}
}

int main(){
	power[0] = 1;
	for(ll i = 1; i < maxn; i++){
		power[i] = power[i-1]*i % mod;
	}
	while(~scanf("%d", &n)){
		init();
		for(int i = 1; i < n; i++){
			scanf("%d %d %lld", &edge[i].u, &edge[i].v, &edge[i].len);
			mapp[edge[i].u].push_back(edge[i].v);
			mapp[edge[i].v].push_back(edge[i].u);
		}
		dfs(1, 0);
		ll ans = 0;
		for(int i = 1; i < n; i++){
			if(p[edge[i].u] == edge[i].v){
				ans = (ans + power[n-1] * have[edge[i].u] % mod * (n - have[edge[i].u]) % mod * edge[i].len % mod) % mod;
			}
			else{
				ans = (ans + power[n-1] * have[edge[i].v] % mod * (n - have[edge[i].v]) % mod * edge[i].len % mod) % mod;
			}
		}
		printf("%lld\n", ans*2 % mod);
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章