hdu6446 网络赛 Tree and Permutation(树形dp求任意两点距离之和)题解
题意:有一棵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求任意两点距离之和)题解的更多相关文章
- 2018中国大学生程序设计竞赛 - 网络选拔赛 hdu Tree and Permutation 找规律+求任意两点的最短路
Tree and Permutation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- HDU 2376 树形dp|树上任意两点距离和的平均值
原题:http://acm.hdu.edu.cn/showproblem.php?pid=2376 经典问题,求的是树上任意两点和的平均值. 这里我们不能枚举点,这样n^2的复杂度.我们可以枚举每一条 ...
- HDU2376Average distance(树形dp|树上任意两点距离和的平均值)
思路: 引:如果暴力枚举两点再求距离是显然会超时的.转换一下思路,我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点数分别为A和B,那 么这条边被经过的次数就是A*B,它对总的距离和的 ...
- HDU 5723 Abandoned country(kruskal+dp树上任意两点距离和)
Problem DescriptionAn abandoned country has n(n≤100000) villages which are numbered from 1 to n. Sin ...
- 吉首大学2019年程序设计竞赛(重现赛)-J(树形DP)
题目链接:https://ac.nowcoder.com/acm/contest/992/J 题意:题意很清晰,就是求任意两点距离的和,结果对1e9+7取模. 思路:裸的树形DP题,一条边的贡献值=这 ...
- Codeforces 791D Bear and Tree Jump(树形DP)
题目链接 Bear and Tree Jumps 考虑树形DP.$c(i, j)$表示$i$最少加上多少后能被$j$整除. 在这里我们要算出所有$c(i, k)$的和. 其中$i$代表每个点对的距离, ...
- [HDU 5293]Tree chain problem(树形dp+树链剖分)
[HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...
- HDU 4514 - 湫湫系列故事——设计风景线 - [并查集判无向图环][树形DP求树的直径]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4514 Time Limit: 6000/3000 MS (Java/Others) Memory Li ...
- 浅谈关于树形dp求树的直径问题
在一个有n个节点,n-1条无向边的无向图中,求图中最远两个节点的距离,那么将这个图看做一棵无根树,要求的即是树的直径. 求树的直径主要有两种方法:树形dp和两次bfs/dfs,因为我太菜了不会写后者这 ...
随机推荐
- 【find -exec】查找并复制文件
find . -name *run_server* -type f -exec cp {} /tmp/ \;
- Assign the task---hdu3974(线段树优化+dfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3974 题意就是:公司有n个员工,关系有n-1个,T x y 代表把工作y交给员工x: 员工可以把工作交 ...
- APICloud-端JS库功能API文档(1)
框架简介: 框架基于APICloud官网端API进行扩展和封装,框架完全采用面向对象编程形式,里面包含APP所使用的常用js功能:js类的自定义(类,构造方法,静态方法,继承...),常用工具函数(验 ...
- UUID生成字符串
在向数据库插入新数据时,可能需要插入字符串形式的ID,这时使用UUID可以生成随机字符串: String str = UUID.randomUUID().toString();
- end=‘’
print('----------------') a = ['aa','bb','cc','dd','ee'] for i in range(len(a)): print(i,a[i])#默认换行 ...
- python 皮尔森相关系数
皮尔森理解 皮尔森相关系数(Pearson correlation coefficient)也称皮尔森积矩相关系数(Pearson product-moment correlation coeffic ...
- vue项目优化
cross-env 包环境 静态文件分离 require 是置顶的 双斜杠 //baidu.com可以是http也可以是https require.ensure打包到不同的文件中 项目文件路径规范 ...
- jQuery 批量操作checkbox
困扰很久的问题: 如果只是 $('input[type=checkbox]').attr('checked',true);//全选 $('input[type=checkbox]').attr('ch ...
- Linux基础命令---cmp
cmp 用字节的方式,比较两个文件是否存在差异,但是不保存运算结果.Cmp指令只会根据结果设置相关的标志位,这个指令之后往往会跟着一个条件跳转指令. 此命令的适用范围:RedHat.RHEL.Ubun ...
- Linux基础命令---dump
dump 检查ext2/3/4文件系统,确定哪些文件需要备份,这些需要备份的文件将会被复制到指定的磁盘或者其他存储介质.dump检查Ext 2/3/4文件系统上的文件,并确定哪些文件需要备份.这些文件 ...