Tree and Permutation

Tree and Permutation

给出一个1,2,3...N的排列,显然全部共有N!种排列,每种排列的数字代表树上的一个结点,设Pi是其中第i种排列的相邻数字表示的结点的距离之和,让我们求sum(Pi)(1<=i<=N!)。

可以设dis(i, j)为树上任意两点间的最短距离,每两点之间的距离都出现了 (N-1)!次,所求答案为 (N-1)! * sum(dis(i, j))。

由于这是一棵树,dis(i, j)的最短路径是唯一的(不存在环),那么对于相邻结点u, v,可以发现边(u, v)走过的次数为左边结点数量*右边结点数量。

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int maxn = 100010;
const int mod = 1e9+7;
typedef long long ll;
typedef pair<int, int> P;

vector<P> G[maxn];
ll fact[maxn], ans;
int n, child[maxn];

void dfs(int u, int fa)///记录下父节点,避免重复遍历父节点
{
//    printf("%d->%d\n", fa, u);
    child[u] = 1;
    int len = G[u].size();
    for(int i=0;i<len;i++)
    {
        int v = G[u][i].first;
        if(v!=fa)
        {
            dfs(v, u);
            child[u] += child[v];
            ans += child[v]*(n-child[v])*G[u][i].second % mod;
            ans %= mod;
        }
    }

}


signed main()
{
    fact[0] = 1;
    for(int i=1;i<maxn;i++)
    {
        fact[i] = fact[i-1] * i % mod;
//        printf("%d %lld\n", i, fact[i]);
    }

    int u, v, d;
    while(scanf("%d", &n)!=EOF)
    {
        memset(child, 0, sizeof(child));
        for(int i=1;i<n;i++)
        {
            scanf("%d %d %d", &u, &v, &d);
            G[u].push_back(P(v, d));
            G[v].push_back(P(u, d));
        }
        ans = 0;
        dfs(1, -1);
        printf("%lld\n", 2*ans*fact[n-1]%mod);

        for(int i=1;i<=n;i++) 
            G[i].clear();
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/liulex/p/11394208.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值