题意:有一棵n个点的树,点之间用无向边相连。现把这棵树对应一个序列,这个序列任意两点的距离为这两点在树上的距离,显然,这样的序列有n!个,加入这是第i个序列,那么这个序列所提供的贡献值为:第一个点到其他所有点距离之和。求所有序列贡献值之和。

思路:假如第一个点是k,那么后面n-1个点共有(n - 1)!种排列,也就是说,第一个点是k那么这样的序列的贡献值为(n - 1)!*(k到其他点距离之和),显然最后答案应该是所有点之间的距离和的两倍 *(n - 1)!。问题转化为了求一棵树上所有点之间的距离,怎么求呢?

假设有一条边E,那么如果要经过E这条边,必然是两个端点在E的两边,假设左边有M点,右边有(n - M)个点,那么一共经过E次数2 *(n - M)* M,所以E的贡献长度为2 *(n - M)* M * E的权值,最后把每条边的贡献长度加在一起就是所有点之间的距离。至于求E两边点数,只要算每个点的子节点数(包括自己)就行了。

MOD值赋错了wa了一下午...写了两个版本...

标解:

参考:HDU2376Average distance(树形dp|树上任意两点距离和的平均值)

代码:

/*DP*/
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = + ;
const int seed = ;
const int MOD = + ;
const int INF = 0x3f3f3f3f;
struct Edge{
ll w;
int u, v, next;
}edge[maxn << ];
ll fac[maxn], dp[maxn], num[maxn], ans;
int head[maxn], tot, n;
void init(){
fac[] = ;
for(int i = ; i < maxn; i++){
fac[i] = (fac[i - ] * i) % MOD;
}
}
void addEdge(ll u, ll v, ll w){
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u, int pre){
num[u] = ;
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].v;
ll w = edge[i].w;
if(v == pre) continue;
dfs(v, u);
num[u] += num[v];
dp[u] = (dp[u] + dp[v] + w * num[v] % MOD * (n - num[v]) % MOD) % MOD;
}
}
int main(){
init();
while(~scanf("%d", &n)){
memset(head, -, sizeof(head));
memset(dp, , sizeof(dp));
tot = ;
for(int i = ; i < n - ; i++){
ll u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
ans = ;
dfs(, -);
ans = dp[] * 2LL % MOD * fac[n - ] % MOD;
printf("%lld\n", ans);
}
return ;
}
/*直接代公式*/
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = + ;
const int seed = ;
const int MOD = + ;
const int INF = 0x3f3f3f3f;
struct Edge{
ll w;
int u, v, next;
}edge[maxn << ];
ll fac[maxn], ans;
int head[maxn], family[maxn], tot, n;
void init(){
fac[] = ;
for(int i = ; i < maxn; i++){
fac[i] = (fac[i - ] * i) % MOD;
}
}
void addEdge(ll u, ll v, ll w){
edge[tot].u = u;
edge[tot].v = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
int dfs(int u, int pre){
family[u] = ;
for(int i = head[u]; i != -; i = edge[i].next){
if(edge[i].v == pre) continue;
family[u] += dfs(edge[i].v, u);
}
return family[u];
}
int main(){
init();
while(~scanf("%d", &n)){
memset(head, -, sizeof(head));
tot = ;
for(int i = ; i < n - ; i++){
ll u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
ans = ;
dfs(, -);
for(int i = ; i < tot; i += ){
ll temp;
temp = (2LL * family[edge[i].v] * (n - family[edge[i].v])) % MOD;
temp = (temp * edge[i].w) % MOD;
temp = (temp * fac[n - ]) % MOD;
ans += temp;
ans %= MOD;
}
printf("%lld\n", ans);
}
return ;
}

hdu6446 网络赛 Tree and Permutation(树形dp求任意两点距离之和)题解的更多相关文章

  1. 2018中国大学生程序设计竞赛 - 网络选拔赛 hdu Tree and Permutation 找规律+求任意两点的最短路

    Tree and Permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  2. HDU 2376 树形dp|树上任意两点距离和的平均值

    原题:http://acm.hdu.edu.cn/showproblem.php?pid=2376 经典问题,求的是树上任意两点和的平均值. 这里我们不能枚举点,这样n^2的复杂度.我们可以枚举每一条 ...

  3. HDU2376Average distance(树形dp|树上任意两点距离和的平均值)

    思路: 引:如果暴力枚举两点再求距离是显然会超时的.转换一下思路,我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点数分别为A和B,那 么这条边被经过的次数就是A*B,它对总的距离和的 ...

  4. HDU 5723 Abandoned country(kruskal+dp树上任意两点距离和)

    Problem DescriptionAn abandoned country has n(n≤100000) villages which are numbered from 1 to n. Sin ...

  5. 吉首大学2019年程序设计竞赛(重现赛)-J(树形DP)

    题目链接:https://ac.nowcoder.com/acm/contest/992/J 题意:题意很清晰,就是求任意两点距离的和,结果对1e9+7取模. 思路:裸的树形DP题,一条边的贡献值=这 ...

  6. Codeforces 791D Bear and Tree Jump(树形DP)

    题目链接 Bear and Tree Jumps 考虑树形DP.$c(i, j)$表示$i$最少加上多少后能被$j$整除. 在这里我们要算出所有$c(i, k)$的和. 其中$i$代表每个点对的距离, ...

  7. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  8. HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...

  9. 浅谈关于树形dp求树的直径问题

    在一个有n个节点,n-1条无向边的无向图中,求图中最远两个节点的距离,那么将这个图看做一棵无根树,要求的即是树的直径. 求树的直径主要有两种方法:树形dp和两次bfs/dfs,因为我太菜了不会写后者这 ...

随机推荐

  1. Git 安装及使用小结

    Git 安装及使用小结 a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline ...

  2. zabbix 3.2.5 agent端(源码包)安装部署 (二)

    一.zabbix agent 端安装部署 1.创建zabbix用户和组 groupadd zabbix useradd -g zabbix zabbix -s /sbin/nologin 2.解压za ...

  3. CSS分列等高

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  4. [py]面向对象图解assignment

    python的chained assignment 在python中 a is b is c 等价于 a is b and b is c 所以,猜猜 False is False is False # ...

  5. POJ1860:Currency Exchange(BF)

    http://poj.org/problem?id=1860 Description Several currency exchange points are working in our city. ...

  6. Linux CentOS6.5下编译安装MySQL 5.6

    检查:卸载掉原有MySql 因为mysql数据库在Linux上实在是太流行了,所以目前下载的主流Linux系统版本基本上都集成了mysql数据库在里面,我们可以通过如下命令来查看我们的操作系统上是否已 ...

  7. Python基础socket编程

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

  8. Redis的设计与实现——字典

    参考博客 绝大多数语言中的字典底层实现基本上都是哈希表.哈希表中用 “负载因子” 来衡量哈希表的 空/满 程度.为了让负载因子在一定的合理范围之内,提高查询的性能,一般的做法是让哈希表扩容,然后reh ...

  9. pycharm跳到指定的行

    ctrl+g  弹出一个框,输入要跳的行数 ctrl+home  光标移到第一行 ctrl+end 光标移到最后一行

  10. vue项目打包后css背景图路径不对的问题

    问题描述: 自己在自学vue做项目的过程中,遇到一个有关背景图片路径的问题,就是css代码中背景图片是根据相对路径来写的,如下图: 当使用npm run dev命令本地访问的时候,背景图片是正常显示的 ...