hdu 4661 Message Passing(木DP&组合数学)
Message Passing
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1187 Accepted Submission(s): 423
messages s/he currently has to another person. What is the minimum number of turns needed so that everyone has all the messages?
This is not your task. Your task is: count the number of ways that minimizes the number of turns. Two ways are different if there exists some k such that in the k-th turn, the sender or receiver is different in the two ways.
Following are T test cases.
For each test case, the first line is number of people, n. Following are n-1 lines. Each line contains two numbers.
Sum of all n <= 1000000.
2
2
1 2
3
1 2
2 3
2
6
pid=5016" target="_blank">5016
5015pid=5014" target="_blank">5014
5013每次共享为一次操作。问每一个人都拥有全部人的信息最小要的次数的共享方法有多少种。
然后能够证明。在最短时间内,全部的传递方式都有一个“信息转换点”——其它节点的信息首先传递到此节点,然后信息再从这个节点向其它节点传递。
事实上我们要求的就是拓扑序有多少种。定义dp[u]表示u节点下面。传到u节点的拓扑序有多少种,cnt[u]表示u有多少个子孙节点,f[i] = i!(i的阶乘)。c[i][j]表示组合数。
如果它有v1,v2,v3个节点。它们的拓扑序分别有dp[v1],dp[v2],dp[v3]这么多种。
那么dp[u] = c[cnt[u]-1][cnt[v1]] * c[cnt[u]-1-cnt[v1]][cnt[v2]]
* c[cnt[u]-1-cnt[v1]-cnt[v2]][cnt[v3]] * dp[v1] * dp[v2] * dp[v3](这个自己推推吧)。化简以后。得到dp[u] = f[cnt[u]-1] / ( f[cnt[v1]] * f[cnt[v2]] * f[cnt[v3]] ) * dp[v1] * dp[v2] * dp[v3] 。我们能够在o(n)的时间复杂度内算出以1节点为根的全部dp值(那么以1为根的答案就算出来了)。以及其它一些辅助信息的值。然后按树的结构往下遍历。分别计算以其它节点为根的答案。以上是网上的思路。我想说的是自己的一点理解。为什么知道每一个子树的拓扑序数目。就能够退出自己的拓扑序数目呢。事实上非常好理解的。当每一个子树的拓扑序定下来之后。确定总顺序的时候。
也就是要得到一个长度为cnt[u]拓扑序列。
对于子树i。
也有一个长度为cnt[i]拓扑序列,所以就要在cnt[u]里找cnt[i]个位置。其它子树再在剩下的子树里找。
还有换根的时候该怎么推导。先写出
由于信息传回去的时候就是你拓扑序嘛。和拓扑序数目一样的。
每个正拓扑序能够和一个逆拓扑序组合。所以就有平方种啦。
#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000010;
#pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long ll;
const ll mod=1e9+7;
ll fac[maxn],dp[maxn],ans;
int cnt,sz[maxn],n;
struct node
{
int v;
node *next;
} ed[maxn<<1],*head[maxn];
void adde(int u,int v)
{
ed[cnt].v=v;
ed[cnt].next=head[u];
head[u]=&ed[cnt++];
}
ll pow_mod(ll x,int k)
{
ll base=x,ret=1;
while(k)
{
if(k&1)
ret=(ret*base)%mod;
base=(base*base)%mod;
k>>=1;
}
return ret;
}
ll ni(ll x){ return pow_mod(x,mod-2); }
void dfs(int fa,int u)
{
ll tp;
dp[u]=tp=sz[u]=1;
for(node *p=head[u];p!=NULL;p=p->next)
{
int v=p->v;
if(v==fa)
continue;
dfs(u,v);
tp=(tp*ni(fac[sz[v]]))%mod;
dp[u]=(dp[u]*dp[v])%mod;
sz[u]+=sz[v];
}
dp[u]=(dp[u]*fac[sz[u]-1]%mod*tp)%mod;
}
void solve(int fa,int u,ll tp)
{
ll tt;
ans=(ans+tp*tp%mod)%mod;
for(node *p=head[u];p!=NULL;p=p->next)
{
int v=p->v;
if(v==fa)
continue;
tt=(tp*fac[n-sz[v]-1]%mod*fac[sz[v]])%mod;
tt=(tt*ni(fac[sz[v]-1])%mod*ni(fac[n-sz[v]]))%mod;
solve(u,v,tt);
}
}
int main()
{
int t,i,u,v,rt; fac[0]=fac[1]=1;
for(i=2;i<maxn;i++)
fac[i]=(i*fac[i-1])%mod;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
cnt=0,ans=0;
for(i=1;i<=n;i++)
head[i]=NULL;
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
adde(u,v);
adde(v,u);
}
rt=(n+1)/2;
dfs(-1,rt);
solve(-1,rt,dp[rt]);
printf("%I64d\n",ans);
}
return 0;
}
版权声明:本文博主原创文章,博客,未经同意不得转载。
hdu 4661 Message Passing(木DP&组合数学)的更多相关文章
- HDU 4661 Message Passing ( 树DP + 推公式 )
参考了: http://www.cnblogs.com/zhsl/archive/2013/08/10/3250755.html http://blog.csdn.net/chaobaimingtia ...
- HDU 4661 Message Passing 【Tree】
题意: 给一棵树,每一个结点都有一个信息,每一个时刻,某一对相邻的结点之间可以传递信息,那么存在一个最少的时间,使得所有的节点都可以拥有所有的信息.但是,题目不是求最短时间,而是求最短时间的情况下,有 ...
- HDU-4661 Message Passing 树形DP,排列组合
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661 题意:有n个人呈树状结构,每个人知道一个独特的消息.每次可以让一个人将他所知的所有消息告诉和他相 ...
- HDU 1003 Max Sum --- 经典DP
HDU 1003 相关链接 HDU 1231题解 题目大意:给定序列个数n及n个数,求该序列的最大连续子序列的和,要求输出最大连续子序列的和以及子序列的首位位置 解题思路:经典DP,可以定义 ...
- hdu 5094 Maze 状态压缩dp+广搜
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092176.html 题目链接:hdu 5094 Maze 状态压缩dp+广搜 使用广度优先 ...
- hdu 2829 Lawrence(斜率优化DP)
题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...
- hdu 4568 Hunter 最短路+dp
Hunter Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- HDU 1231.最大连续子序列-dp+位置标记
最大连续子序列 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- HDU 1078 FatMouse and Cheese ( DP, DFS)
HDU 1078 FatMouse and Cheese ( DP, DFS) 题目大意 给定一个 n * n 的矩阵, 矩阵的每个格子里都有一个值. 每次水平或垂直可以走 [1, k] 步, 从 ( ...
随机推荐
- oracle 12c 中asm元数据是否有所变化
详见原文博客链接地址: oracle 12c 中asm元数据是否有所变化
- Android中的动画具体解释系列【4】——Activity之间切换动画
前面介绍了Android中的逐帧动画和补间动画,并实现了简单的自己定义动画.这一篇我们来看看怎样将Android中的动画运用到实际开发中的一个场景--Activity之间跳转动画. 一.定义动画资源 ...
- redis优化配置和redis.conf说明
1. redis.conf 配置參数: #是否作为守护进程执行 daemonize yes #如以后台进程执行,则需指定一个pid,默觉得/var/run/redis.pid pidfile redi ...
- AppWidget应用(二)---PendingIntent 之 getActivity
通过AppWidget应用(一)的介绍,我们已经知道如何创建一个在主界面上显示一个appWidget窗口,但这并不是我们的目的,我们需要做到程序与用户之间进行交互:下面来介绍下如何通过appWidge ...
- hdoj 1395 2^x mod n = 1 【暴力】
策略 : 观察可知,1 或者是能被2整除的数都不会求余等于1, 仅仅须要推断一下是不是除1之外的奇数,在依次查找2^x(mod(n)) ? = 1就能够了 难点:假设每次都是在原来的基础上×2 再推断 ...
- c#怎样获取excel单元格的RGB颜色
这段时间一直在做office的工作.前2天获取单元格的颜色的问题一直没搞明确. 開始我想用的就是Npoi.主要前一部分的工作都是用Npoi完毕的 row.GetCell(j).CellStyle.Fi ...
- Java&Android反编工具打包
Java&Android反编工具: 1.Eclipse反编插件:安装到Eclipse后,可以简要的查看jar包中的*.class; 2.DoAPK:反编*.apk为smali和一些资源文件,可 ...
- python学习笔记之七:魔法方法,属性
在python中,有的名称会在前面和后面加上两个下划线,由这些名字组成的集合所包含的方法称为魔法方法(或者是特殊方法).如果对象实现了这些方法中的某一个,那么这个方法会在特殊的情况下(确切地说是根据名 ...
- PHP 类属性 类静态变量的访问
php的类属性其实有两种,一种是类常量,一种是类静态变量.两种容易引起混淆. 如同静态类方法和类实例方法一样,静态类属性和实例属性不能重定义(同名),但静态属性可以和类常量同名. <?php c ...
- ftk学习记(消息框篇)
[ 声明:版权全部,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 上一篇说到了输入框.闲话不多说,首先看结果显示, 大家看看效果是不是和我们之前说的一样.今天, ...