题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4661

  题意:有n个人呈树状结构,每个人知道一个独特的消息。每次可以让一个人将他所知的所有消息告诉和他相邻的人。求所有人都知道所有消息花时花的步数最少的所有方案数。

  首先需要满足的是最小的步数,所以我们一定是先把所有消息先传到一个人手中才是最优的,然后再从这个人传回去,也就是每条边走两次。我们只需要考虑单向传到某个人的方案数cnt,因为再传回去也是cnt。那么我们可以枚举每个点为收集点,把所有的和加起来就是答案。这里就是一个树形DP的问题,转移的时候是一个组合问题:记录f[u],cnt[u],f[u]为以u为根的子树的拓扑排序数,cnt[u]为以u为子树的节点个数。这里,涉及到如何合并两个子树,比如u的两个子树v1,v2,那么合并后的拓扑排序数为:f[u]=f[son1]*f[son2]*C(cnt[son1]+cnt[son2],cnt[son1]),也就是:

  这里只求出了根节点的方案,还要再做一次搜索,把其它点的方案求出了,根据上面那个公式推一下就可以了。。。

 //STATUS:C++_AC_3062MS_49796KB
#include <functional>
#include <algorithm>
#include <iostream>
//#include <ext/rope>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
//using namespace __gnu_cxx;
//define
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1.0)
//typedef
typedef __int64 LL;
typedef unsigned __int64 ULL;
//const
const int N=;
const int INF=0x3f3f3f3f;
const LL MOD=,STA=;
const LL LNF=1LL<<;
const double EPS=1e-;
const double OO=1e30;
const int dx[]={-,,,};
const int dy[]={,,,-};
const int day[]={,,,,,,,,,,,,};
//Daily Use ...
inline int sign(double x){return (x>EPS)-(x<-EPS);}
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
//End LL fac[N],rev[N],f[N],cnt[N];
int T,n;
LL ans;
vector<int> q[N]; void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(!b){d=a;x=;y=;}
else {exgcd(b,a%b,d,y,x);y-=x*(a/b);}
} LL inv(LL a,LL n)
{
LL d,x,y;
exgcd(a,n,d,x,y);
return (x+n)%n;
} void dfs1(int u,int fa)
{
int i,v;
cnt[u]=f[u]=;
for(i=;i<q[u].size();i++){
if((v=q[u][i])==fa)continue;
dfs1(v,u);
cnt[u]+=cnt[v];
f[u]=((f[u]*f[v])%MOD*rev[cnt[v]])%MOD;
}
f[u]=(f[u]*fac[cnt[u]-])%MOD;
} void dfs2(int u,int fa)
{
int i,v;
if(u!=){
f[u]=(f[fa]*cnt[u])%MOD*inv(n-cnt[u],MOD)%MOD;
ans=(ans+f[u]*f[u]%MOD)%MOD;
}
for(i=;i<q[u].size();i++){
if((v=q[u][i])==fa)continue;
dfs2(v,u);
}
} int main(){
// freopen("in.txt","r",stdin);
int i,j,a,b;
fac[]=;
for(i=;i<N;i++)fac[i]=(i*fac[i-])%MOD;
for(i=;i<N;i++)rev[i]=inv(fac[i],MOD);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=;i<=n;i++)q[i].clear();
for(i=;i<n;i++){
scanf("%d%d",&a,&b);
q[a].push_back(b);
q[b].push_back(a);
} dfs1(,);
ans=f[]*f[]%MOD;
dfs2(,); printf("%I64d\n",(ans+MOD)%MOD);
}
return ;
}

HDU-4661 Message Passing 树形DP,排列组合的更多相关文章

  1. HDU 4661 Message Passing ( 树DP + 推公式 )

    参考了: http://www.cnblogs.com/zhsl/archive/2013/08/10/3250755.html http://blog.csdn.net/chaobaimingtia ...

  2. hdu 4661 Message Passing(木DP&amp;组合数学)

    Message Passing Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Other ...

  3. HDU 4661 Message Passing 【Tree】

    题意: 给一棵树,每一个结点都有一个信息,每一个时刻,某一对相邻的结点之间可以传递信息,那么存在一个最少的时间,使得所有的节点都可以拥有所有的信息.但是,题目不是求最短时间,而是求最短时间的情况下,有 ...

  4. 【BZOJ】2111: [ZJOI2010]Perm 排列计数 计数DP+排列组合+lucas

    [题目]BZOJ 2111 [题意]求有多少1~n的排列,满足\(A_i>A_{\frac{i}{2}}\),输出对p取模的结果.\(n \leq 10^6,p \leq 10^9\),p是素数 ...

  5. 【BZOJ】4559: [JLoi2016]成绩比较 计数DP+排列组合+拉格朗日插值

    [题意]n位同学(其中一位是B神),m门必修课,每门必修课的分数是[1,Ui].B神碾压了k位同学(所有课分数<=B神),且第x门课有rx-1位同学的分数高于B神,求满足条件的分数情况数.当有一 ...

  6. G.subsequence 1(dp + 排列组合)

    subsequence 1 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 You are ...

  7. HDU 5816 状压DP&排列组合

    ---恢复内容开始--- Hearthstone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java ...

  8. 2017ACM暑期多校联合训练 - Team 8 1011 HDU 6143 Killer Names (容斥+排列组合,dp+整数快速幂)

    题目链接 Problem Description Galen Marek, codenamed Starkiller, was a male Human apprentice of the Sith ...

  9. 【noi 2.6_9288】&【hdu 1133】Buy the Ticket(DP / 排列组合 Catalan+高精度除法)

    题意:有m个人有一张50元的纸币,n个人有一张100元的纸币.他们要在一个原始存金为0元的售票处买一张50元的票,问一共有几种方案数. 解法:(学习了他人的推导后~) 1.Catalan数的应用7的变 ...

随机推荐

  1. int main(int argc,char* argv[])参数详解

    argc是命令行总的参数个数 argv[]是argc个参数,其中第0个参数是程序的全名,以后的参数 命令行后面跟的用户输入的参数,比如: int main(int argc, char* argv[] ...

  2. Google面试题及答案

    1. 村子里有100对夫妻,其中每个丈夫都瞒着自己的妻子偷情...村里的每个妻子都能立即发现除自己丈夫之外的其他男人是否偷情,唯独不知道她自己的丈夫到底有没有偷情.村里的规矩不容忍通奸.任何一个妻子, ...

  3. kruskal --- c++ (2)

    #include <cstdio> #include <algorithm> using namespace std; struct aaa{ int l,r,w; bool ...

  4. eclipse不能创建java虚拟机-解决方法

    找到eclipse目录下的eclipse.ini,可以看到如下内容: -startup plugins/org.eclipse.equinox.launcher_1.1.0.v20100507.jar ...

  5. mvc异步表单遇到的问题

    1,mvc异步表单遇到的问题    问题:使用jqury easy ui 时提交异步数据不能请求到服务器   解决办法:经过细心调试和检测,发现jqury的加载顺序放在了easy ui之后,所以首先加 ...

  6. 原码 & 反码 & 补码 & 详解

    本篇文章讲解了计算机的原码, 反码和补码. 并且进行了深入探求了为何要使用反码和补码, 以及更进一步的论证了为何可以用反码, 补码的加法计算原码的减法. 论证部分如有不对的地方请各位牛人帮忙指正! 希 ...

  7. PHP创建XML文件讲解

    <?php   #code by coder_apex 2007-6-15   #自动生成一个如下的XML文件   #   #       <?xml version="1.0& ...

  8. Linux操作系统下软件的安装方法大全

    一.rpm包安装方式步骤: 1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录: 2.打开一个终端,su -成root用户: 3.cd soft.version.rpm所在 ...

  9. Scrum敏捷开发简介

    Agile 敏捷开发实践中,强调团队的自我管理.在 Scrum 中,自我团队管理体现在每天的 Scrum 会议中和日常的协同工作,在每天的 Scrum 例会中,团队成员一般回答一下几个问题 : 昨天完 ...

  10. Unity3D研究院之打开Activity与调用JAVA代码传递参数

    原地址:http://www.xuanyusong.com/archives/667    Unity for Android 比较特殊,Unity for IOS 打包是将XCODE工程直接交给开发 ...