HDU 6446 Tree and Permutation【思维】好题!

传送门
题意: 给定一个n, 那么1-n是一个排列, 定义某个排列(x y z)的值为x - y, x - z在树上的最短距离和, 求这个排列的全排列的值相加等于多少, 树的形态会给出.

思路: 算边的贡献, 首先对于任意一个排列, 它是树上某点到其他点的距离之和, 然后由于全排列, 实际上就是树上任意两点之间的距离之和(考虑顺序), 首先树上任意两点之间的和我们会求(考虑每条边的贡献, 即边的两边的端点数量)

int siz[maxn]; ll ans = 0;
void dfs(int u, int fa) {
    siz[u] = 1;
    for (int i = 0 ; i < sz(ve[u]) ; ++ i) {
        int to = ve[u][i];
        if (to == fa) continue;
        dfs(to, u);
        ans += 1ll * (n - siz[to]) * siz[to] * 2;// (* len) 如果有边长的话
        siz[u] += siz[to];
    }
}

那么这里的多的排列, 实际上又多边的贡献有那些影响了?观察任意一个排列可知, 固定第一个点不动, 那么第一个点对后面的点总的贡献就是(n-1)!, 即后面n-1个点全排列都要算进去, 所以这道题就是在上面代码的基础上最后在乘一个(n-1)!就是答案了…
AC Code

const int maxn = 1e5+5;
struct node {
    int to, next; ll w;
}e[maxn<<1];
int cnt, head[maxn];
ll fac[maxn];
void init2() {
    fac[0] = 1;
    for (int i = 1 ; i < maxn ; i ++) {
        fac[i] = fac[i-1] * i % mod;
    }
}
void init() {
    cnt = 0; Fill(head, -1);
}
void add(int u, int v, ll w) {
    e[cnt] = node{v, head[u], w};
    head[u] = cnt++;
}
int siz[maxn], n; ll ans;
void dfs(int u, int fa) {
    siz[u] = 1;
    for (int i = head[u]; ~i ; i = e[i].next) {
        int to = e[i].to;
        if (to == fa) continue;
        dfs(to, u);
        ans += (1ll*n-siz[to])*1ll*siz[to]%mod*2*e[i].w%mod;
        ans %= mod;
        siz[u] += siz[to];
    }
}
void solve() {
    init2();
    while(~scanf("%d", &n)) {
        init();
        for (int i = 1 ; i < n ; i ++) {
            int u, v; ll w;
            scanf("%d%d%lld", &u, &v, &w);
            add(u, v, w); add(v, u, w);
        }
        ans = 0; dfs(1, -1);
        ans = ans*fac[n-1]%mod;
        printf("%lld\n", ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值