[2015hdu多校联赛补题]hdu5378 Leader in Tree Land
2015-08-12 22:41
519 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5378
题意:给你一棵n个结点的有根树。因为是有根树,那么每个结点可以指定以它为根的子树(后面讨论的子树都是这个)。现在我们把标号从1到n的n个minister派驻到这些结点上面(每个结点派驻一人),并规定任一子树中编号最大的minister 为该子树的领导,问你存在多少个不同的领导
解:
引用官方题解:
View Code
题意:给你一棵n个结点的有根树。因为是有根树,那么每个结点可以指定以它为根的子树(后面讨论的子树都是这个)。现在我们把标号从1到n的n个minister派驻到这些结点上面(每个结点派驻一人),并规定任一子树中编号最大的minister 为该子树的领导,问你存在多少个不同的领导
解:
引用官方题解:
可以用求概率的思想来解决这个问题。令以i号节点为根的子树为第i棵子树,设这颗子树恰好有sz[i]个点。那么第i个点是第i棵子树最大值的概率为1/sz[i],不是最大值的概率为(sz[i]-1)/sz[i]。现在可以求解恰好有k个最大值的概率。 令dp[i][j]表示考虑编号从1到i的点,其中恰好有j个点是其子树最大值的概率。 很容易得到如下转移方程:dp[i][j]=dp[i-1][j]*(sz[i]-1)/sz[i]+dp[i-1][j-1]/sz[i]。这样dp [k]就是所有点中恰好有k个最大值的概率。 题目要求的是方案数,用总数n!乘上概率就是答案。计算的时候用逆元代替上面的分数即可
/* * Problem: hdu5378 Leader in Tree Land * Author: SHJWUDP * Created Time: 2015/8/12 星期三 20:17:31 * File Name: 1006.cpp * State: Accepted * Memo: 概率dp,乘法逆元 */ #include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; const int MOD=1e9+7; struct Edge { int u, v; }; int n, k; vector<Edge> edges; vector<vector<int> > G; vector<int> siz, inv; ///siz[i]*inv[i]=1(mod 1e9+7) void init() { edges.clear(); G.assign(n+1, vector<int>(0)); siz.resize(n+1); inv.resize(n+1); } void addEdge(int u, int v) { edges.push_back((Edge){u, v}); G[u].push_back(edges.size()-1); } int pow_mod(long long x, int n, int mod) { long long res=1; while(n) { if(n & 1) res=res*x%mod; x=x*x%mod; n>>=1; } return res; } void dfs(int u, int fa) { siz[u]=1; for(int i : G[u]) { Edge & e=edges[i]; if(e.v==fa) continue; dfs(e.v, u); siz[u]+=siz[e.v]; } } int main() { #ifndef ONLINE_JUDGE freopen("in", "r", stdin); //freopen("out", "w", stdout); #endif int T, now=0; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &k); init(); for(int i=0; i<n-1; i++) { int a, b; scanf("%d%d", &a, &b); addEdge(a, b); addEdge(b, a); } dfs(1, -1); for(int i=1; i<=n; i++) inv[i]=pow_mod(siz[i], MOD-2, MOD); //求siz[i]的乘法逆元 vector<vector<long long> > f(n+1, vector<long long>(n+1, 0)); f[0][0]=1; for(int i=1; i<=n; i++) { for(int j=0; j<=k; j++) { f[i][j]+=f[i-1][j]*(siz[i]-1)%MOD*inv[i]%MOD; if(j>0)f[i][j]+=f[i-1][j-1]*inv[i]%MOD; f[i][j]%=MOD; } } long long ans=f [k]; for(int i=1; i<=n; i++) { ans=(ans*i)%MOD; } printf("Case #%d: ", ++now); printf("%I64d\n", ans); } return 0; }
View Code
相关文章推荐
- 【LeetCode】Product of Array Except Self
- 线程同步之生产者消费者
- 性能面试题汇总
- java设计模式-工厂模式学习笔记
- java设计模式-工厂模式学习笔记
- scala2.10.x case classes cannot have more than 22 parameters
- scala2.10.x case classes cannot have more than 22 parameters
- scala2.10.x case classes cannot have more than 22 parameters
- 好的商业模式就是用技术打开的想象
- DCIM 用 UIScrollView 和UIPageControl
- ViewDragHelper详解
- scala2.10.x case classes cannot have more than 22 parameters
- SQLite基础学习
- 转载:Ant学习笔记——自己构建Ant编译环境
- unix网络编程
- (转载)Convolutional Neural Networks卷积神经网络
- centos6.5 设置ssh无密码登录
- 不确定的问题 2015-8-12
- (一二一)核心动画基础
- android控件--ViewPager原理及实现