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,因为我太菜了不会写后者这 ...
随机推荐
- 2015 湘潭大学程序设计比赛(Internet)--D题-最小的数
最小的数 Accepted : 47 Submit : 276 Time Limit : 1000 MS Memory Limit : 65536 KB 题目描述 给你一个n位数,每次操作可以 ...
- oracle(四) 常用语句
1.分页 select t2.* from (select rownum row, t1.* from your_table where rownum < ?) t2 where t2.row ...
- 第十八篇:融汇贯通--谈USB Video Class驱动
USB Video Class驱动是WINDOWS系统包含的一个针对于USB VIDEO 类的驱动程序. 好多project师都做过USB VIDEO设备端的开发, 基本的工作内容为: 使用FIRMW ...
- Sql Server 2016 Always On集群搭建
第一步,配置好windows环境 第二步 (配置内容较多--需单写) 需要做windows集群 安装WSFC集群组件 直接在Windows服务器管理工具中,增加功能模块,集群故障转移模块 并增加节点 ...
- transition使用
- phpQuery中文手册(更新中)
示例 phpQuery::newDocumentFileXHTML('my-xhtml.html')->find('p'); $ul = pq('ul'); 载入文档 phpQuery::new ...
- elasticsearch 6.0java api的使用
elasticsearch 6.0 中java api的使用 1:使用java api创建elasticsearch客户端 package com.search.elasticsearch; impo ...
- PAT 1066 Root of AVL Tree[AVL树][难]
1066 Root of AVL Tree (25)(25 分) An AVL tree is a self-balancing binary search tree. In an AVL tree, ...
- dialog提交表单
<div id="dialog" title="添加客户"> <!--表单提交--> <form id="dialogF ...
- entity framework 新增,更新,事务
protected void Button1_Click(object sender, EventArgs e) { yyEntities _db; _db = new yyEntities(); t ...