题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4900
Problem Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

If you solved the last problem, you will see that the devil can't figure out who is z*p because there are too many people. So anyway, she decided to let it go.

The devil think she is the cutest loli in the world, but there is some people in the kingdom don't think so. And they think WJMZBMR is the most cutest loli.

It seems a war is approaching, but in this kingdom, due to the old tradition, every conflict is solved by Algorithm contest!

One day, WJMZBMR is hanging out with her friend s***kplus on the street. And she noticed that there is a group of people playing algorithm contest to decide who is the cutest loli in the kingdom. One problem attracts her interest:

Given a tree with n vertices, we randomly choose k vertices of it. Then we can induced a subtree which is the smallest connected subtree of the original tree containing those k vertices.

Each vertex has a label(an integer), for a subtree we induced, we look at its diameter a-b,(if there are many diameters, pick the one with the smallest a, and then the smallest b). And output how many distinct label are on the diameter.

What is the expected value we output?

Of course, WJMZBMR is merely a cute loli and don't know much about the algorithm contest, but since you are a member of Princess's Knight, you should solve it for your princess, can you do it?

 
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains two integers n,k.
The next n-1 lines, each contains two integers a and b, denote there is an edge between a and b.
The next line contains n integers separated by a single space, denote each vertex's label in the order from 1 to n.

n,k <= 300. label <= 10^9.
T <= 20.

 
Output
For each case, output the result.
This problem is special judged. The relative error less than 1e-6 will be accepted.

题目大意:给一棵树,每个点有一个权值,边长为1。随机选择k个点,选上使得这k个点连通的最少点,连上边,设其字典序最小的直径为path(a, b),令path(a, b)上不同权值的点的个数为t。求t的期望。

思路:先放上CLJ的官方题解:

不妨枚举a,b作为直径,然后计算该情况的概率。注意到如果不考虑字典序这其实等价于其它选的点满足Dc→a ≤ Da→b  并且 Dc→b ≤ Da→b。

考虑字典序也类似。

首先这里是一条求树的直径的题目:POJ 2631 Roads in the North(求树的直径,两次遍历 or 树DP)

这里面的第一个解法的证明可以得出一个结论①:从一个点开始搜索,离这个点最远的点,一定是这棵树的其中一个直径的一个端点。

设mat[a][b]为a→b的简单路径的距离,下面设a < b。

结论②:对于a、b两点,把所有max(mat[i][a], mat[i][b]) ≤ mat[a][b]的点选上,其诱导子图中,path(a, b)是其中一条直径。

证明:利用由mat[i][a] ≤ mat[a][b]得,b是离a最远的点之一。由结论①得,b是直径的端点。同理可得a是离b最远的点之一,那么可得path(a, b)是一条直径。

结论③:在②的前提下,选择点 i 当且仅当没有(mat[i][b] == mat[a][b] && i < a)和(mat[i][a] == mat[a][b] && i < b),此时path(a, b)是字典序最小的直径。

必要性:若有mat[i][b] == mat[a][b] && i < a,那么有直径path(i, b),字典序小于path(a, b),否决。若有mat[i][a] == mat[a][b] && i < b,那么有直径path(a, i),字典序小于path(a, b)。

充分性:若存在直径path(i, a),那么i > b > a,那么path(a, i)字典序小于path(i, a),path(a, i)字典序小于path(a, b)。

若存在直径path(b, i),由于b > a且i > a,则path(b, i)与path(i, b)字典序小于path(a, b)。

假设存在直径path(i, j)。那么有mat[i][j] = mat[a][b]。这种情况出现当且仅当path(i, j)和path(a, b)的交汇点是path(a, b)的中点,此时有path(i, a) = path(j, a) = path(a, b),由上面的可知,(i, j)的字典序小于path(a, b)。

结论④:结论③所诱导出来的子图是符合条件的极大诱导子图。

证明:随意加入一个点,path(a, b)都不再是字典序最小的直径。

先预处理出每对点之间的距离mat[a][b],再预处理出每对点之间不同权值的点的个数dif[a][b]。

在预处理出阶乘的对数,算组合数c(n, k)的时候使用阶乘来O(1)计算,算好后再exp一下,提高精度。至于不这么做能不能过我就不知道了,这是我能想到精度最高的方法了。

接下来,就是枚举a、b。其中a < b。对于每个(a, b),若子图点数cnt大于k个点,那么累加ans += dif[a][b] * c(cnt - 2, k - 2) / c(n, k)。

PS:k=1时这里输出0。几个小时的人生。

代码(1453MS):

 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std; const int MAXN = ;
const int INF = 0x3f3f3f3f; int mat[MAXN][MAXN], dif[MAXN][MAXN];
int label[MAXN], hash[MAXN], tmp[MAXN];
int n, k, T; int head[MAXN], ecnt;
int to[MAXN << ], next[MAXN << ]; void init() {
memset(head + , -, n * sizeof(int));
ecnt = ;
} void add_edge(int u, int v) {
to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
} int que[MAXN], dis[MAXN]; void bfs(int st) {
memset(dis + , 0x3f, n * sizeof(int));
int l = , r = ;
dis[que[r++] = st] = ;
while(l != r) {
int u = que[l++];
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(dis[u] + < dis[v]) {
dis[v] = dis[u] + ;
que[r++] = v;
}
}
}
for(int i = ; i <= n; ++i) mat[st][i] = dis[i];
} int cnt[MAXN]; void dfs(int u, int f, int& c, int st) {
if(++cnt[hash[u]] == ) c++;
dif[st][u] = c;
for(int p = head[u]; ~p; p = next[p]) {
int &v = to[p];
if(v == f) continue;
dfs(v, u, c, st);
}
if(--cnt[hash[u]] == ) c--;
}
//排列组合
double per[MAXN];
void initPer(int n = ) {
per[] = log();
for(int i = ; i <= n; ++i)
per[i] = per[i - ] + log(i);
}
double c(int n, int k) {
return per[n] - per[n - k] - per[k];
} double calc(int a, int b) {
int cnt = ;
for(int i = ; i <= n; ++i) {
if(i == a || i == b) continue;
if(mat[i][a] > mat[a][b] || mat[i][b] > mat[a][b]) continue;
if(mat[i][b] == mat[a][b] && i < a) continue;
if(mat[i][a] == mat[a][b] && i < b) continue;
cnt++;
}
if(cnt >= k) return dif[a][b] * exp(c(cnt - , k - ) - c(n, k));
else return ;
} double solve() {
if(n < k || k == ) return ;
if(k == ) return ;
double res = ;
for(int i = ; i <= n; ++i) {
for(int j = i + ; j <= n; ++j) {
res += calc(i, j);
}
}
return res;
} int main() {
initPer();
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &k);
init();
for(int i = , a, b; i < n; ++i) {
scanf("%d%d", &a, &b);
add_edge(a, b);
}
for(int i = ; i <= n; ++i) bfs(i); for(int i = ; i <= n; ++i) scanf("%d", &hash[i]);
int cnt = ;
for(int i = ; i <= n; ++i) tmp[cnt++] = hash[i];
sort(tmp, tmp + cnt);
cnt = unique(tmp, tmp + cnt) - tmp;
for(int i = ; i <= n; ++i) hash[i] = lower_bound(tmp, tmp + cnt, hash[i]) - tmp;
for(int i = , c = ; i <= n; ++i) dfs(i, , c, i); printf("%.10f\n", solve());
}
}

HDU 4900 NO ACM NO LIFE(概率+枚举+搜索)(2014 Multi-University Training Contest 4)的更多相关文章

  1. hdu 2818 Building Block(加权并查集)2009 Multi-University Training Contest 1

    题意: 一共有30000个箱子,刚开始时都是分开放置的.接下来会有两种操作: 1. M x y,表示把x箱子所在的一摞放到y箱子那一摞上. 2. C y,表示询问y下方有多少个箱子. 输入: 首行输入 ...

  2. hdu 3047 Zjnu Stadium(加权并查集)2009 Multi-University Training Contest 14

    题意: 有一个运动场,运动场的坐席是环形的,有1~300共300列座位,每列按有无限个座位计算T_T. 输入: 有多组输入样例,每组样例首行包含两个正整数n, m.分别表示共有n个人,m次操作. 接下 ...

  3. hdu 3461 Code Lock(并查集)2010 ACM-ICPC Multi-University Training Contest(3)

    想不到这还可以用并查集解,不过后来证明确实可以…… 题意也有些难理解—— 给你一个锁,这个所由n个字母组成,然后这个锁有m个区间,每次可以对一个区间进行操作,并且区间中的所有字母要同时操作.每次操作可 ...

  4. hdu 3938 Portal(并查集+离线+kruskal)2011 Multi-University Training Contest 10

    搜了题解才把题搞明白.明白之后发现其实题意很清晰,解题思路也很清晰,只是题目表述的很不清晰…… 大意如下—— 给你一个无向图,图中任意两点的距离是两点间所有路径上的某一条边,这条边需要满足两个条件:1 ...

  5. HDU 6356.Glad You Came-线段树(区间更新+剪枝) (2018 Multi-University Training Contest 5 1007)

    6356.Glad You Came 题意就是给你一个随机生成函数,然后从随机函数里确定查询的左右区间以及要更新的val值.然后最后求一下异或和就可以了. 线段树,区间最大值和最小值维护一下,因为数据 ...

  6. HDU 4610 Cards (合数分解,枚举)

    Cards Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  7. HDU 4326Game(比较难理解的概率dp)

    Game Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Subm ...

  8. HDU 4336 Card Collector(动态规划-概率DP)

    Card Collector Problem Description In your childhood, do you crazy for collecting the beautiful card ...

  9. HDU校赛 | 2019 Multi-University Training Contest 6

    2019 Multi-University Training Contest 6 http://acm.hdu.edu.cn/contests/contest_show.php?cid=853 100 ...

随机推荐

  1. 图片放大方法、、菜单栏的位置随滚轮移动固定方法、、<a></a>去外层虚线方法:a:focus { outline:none; -moz-outline:none;};

    图片放大方法一: <style type="text/css">.xt{ width:230px; height:230px;}.tp{ width:230px; he ...

  2. Android 4.2蓝牙介绍

    蓝牙一词源于公元十世纪丹麦国王HaraldBlatand名字中的Blatand.Blatand的英文之意就是Blue tooth.这是因为这位让丹麦人引以为傲的国王酷爱吃蓝莓以至于牙龈都被染成蓝色.由 ...

  3. 我的第一个chrome扩展(3)——继续读样例

    1.操作用户正在浏览的界面 http://www.ituring.com.cn/article/60212 问题:1.google未定义ID,用name为何无法找到? 2.如何让整个按钮一起动?原函数 ...

  4. ManualResetEvent和AutoResetEvent的区别实例

    ManualResetEvent和AutoResetEvent的作用可以理解为在线程执行中插入停顿点flag终止程序运行,然后通过设置flag的状态来使得程序继续运行. 两者的区别是:ManualRe ...

  5. 树莓派如何便捷的使用pi4j

    问题的由来 pi4j用起来很方便,但是感觉pi4j库的命名太杂乱,啰嗦了,很容易弄混,而且好像没听说官方有自己的编译器.如果没有智能点的编辑器的话,写起来真要命,但是树莓派运行Eclipse不太现实, ...

  6. C++ 简单中文敏感词检测工具类

    具体思路: 1->敏感词库,可从数据库读取,也可以从文件加载. 2->将敏感词转化为gbk编码,因为gbk严格按照字符一个字节,汉字两个字节的格式编码,便于容易切分文字段. 3->将 ...

  7. UML学习

    学习链接:http://blog.csdn.net/wangyongxia921/article/category/1293975 感谢原文作者.

  8. 20145211 《Java程序设计》实验报告三:敏捷开发与XP实践

    实验内容 使用 git上传代码 使用 git相互更改代码 实现代码的重载 XP基础 XP核心实践 相关工具 一.git上传代码 这一部分是与我的partner合作的,详见他的博客- 20145326蔡 ...

  9. windows下安装yaf和git

    不得不说win7下安装yaf比mac下安装yaf简单多了 1. phpinof()看一下你的php版本.我的是php 5.4所以我选择是php_yaf-2.1.9-x86-5.4-zts-nodebu ...

  10. 使用C语言把字母转换成大写,不能使用库函数

    char to_upper(char input) {   if ('a' <= input && input <= 'z') {     return input - ' ...