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

 

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