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] 步, 从 ( ...
随机推荐
- 2014最新SSH框架面试题大收集
(1)Hibernate工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Sesssion 4.创建事务Transati ...
- 【C#遗补】获取应用程序路径之System.IO.Directory.GetCurrentDirectory和System.Windows.Forms.Application.StartupPath的区别
原文:[C#遗补]获取应用程序路径之System.IO.Directory.GetCurrentDirectory和System.Windows.Forms.Application.StartupPa ...
- poj3268(最短路)
题目连接:http://poj.org/problem?id=3268 题意:给出n个点和m条单向边,现在所有牛要到牛x那里去参加聚会,并且所有牛参加聚会后还要回来,给你牛x,除了牛x之外的牛,他们都 ...
- poj 2769 Reduced ID Numbers(memset使用技巧)
Description T. Chur teaches various groups of students at university U. Every U-student has a unique ...
- 如何收集 EBS 各种相关业务的表的数据
1. Receiving 相关 參照 Note: 402245.1, 跑 rcv11i_sa.sql 就能够, 输入 po number, 其余默认. 參照 Note: 1294177.1, 假设上面 ...
- Redis设计与实现读书笔记——双链表
前言 首先,贴一下参考链接: http://www.redisbook.com/en/latest/internal-datastruct/adlist.html, 另外真赞文章的作者,一个90后的小 ...
- Jedis Client的使用以及序列化
JedisPool pool = new JedisPool(poolConfig, IP, PORT, timeout); public String set(String key,String v ...
- 怎样从host之外连接到docker container
启动docker的时候的指令使用 sudo docker -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock -d & 这样就能使dock ...
- Cocos2d-x中父节点scale对子节点的影响
背景:在前几天,刚接触cocos2d-x,随便找了一张图,作为一个CCSprite,而且设置了scale属性,然后在这个sprite上创建了一个CCLabelTTF,并用sprite->addC ...
- poj3176--Cow Bowling(dp:数塔问题)
Cow Bowling Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14028 Accepted: 9302 Desc ...