首先这是一道dp题,对题意的把握和对状态的处理是解题关键。

题目给出的范围是n在1到1e11之间,由于在裂变过称中左儿子总是父亲节点的一个非平凡约数,容易看出裂变过程只与

素数幂有关,并且显然有素数不超过11个,幂指数不超过40,实际上可以用一个大小为11的数组来等价地表示状态,状态

与其内元素顺序无关,因此可以排序,压缩后的状态不超过3000个(准确地说是2957个,通过一个简单的dfs即可统计出此结果)。

以上解决了题目的规模问题。

这道题目我开始因为理解错题意wa了几次,不能通过统计儿子节点的期望高度的平均值再加1得到以父节点为根的数的期望高度,因为两颗子树

的高度在概率上对根树的影响不是相互独立的。

可以设dp(i, j)为以状态i为根深度为j的概率:

那么显然有dp(i, j) = sigma(dp(k, j - 1) * sigma(i / k, t) + sigma(k, t) * dp(i / k, j - 1) + dp(k, j - 1) * dp(i / k, j -1)) / (N - 2)

其中k | i, 且 k ≠ 1,k≠ i, t < j - 1。

以状态i为根的树的期望高度:exp(i) = sigma(j * dp(i, j)), 0 < j < 40.

因此状态转移可以通过枚举左儿子得到,整体复杂度O(3000 * 3000 * 40)。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <map>
  5. #include <string>
  6. #include <vector>
  7. #include <set>
  8. #include <cmath>
  9. #include <ctime>
  10. #include <cassert>
  11. #pragma comment(linker, "/STACK:102400000,102400000")
  12. #define lson (u << 1)
  13. #define rson (u << 1 | 1)
  14. #define cls(i, j) memset(i, j, sizeof i)
  15. using namespace std;
  16. typedef __int64 ll;
  17. const double eps = 1e-;
  18. const double pi = acos(-1.0);
  19. const int maxn = 1e5 + ;
  20. const int maxm = ;
  21. const int inf = 0x3f3f3f3f;
  22. const ll linf = 0x3fffffffffffffff;
  23. const ll mod = 1e9 + ;
  24.  
  25. int debug = ;
  26. map<ll, int> mapi;
  27. int buf[], k1;
  28. ll S = (ll)1e11;
  29. double dp[][];
  30.  
  31. int a[] = {, , , , , , , , , , };
  32. bool cmp(int a, int b) { return a > b; }
  33. int prime[maxn], k;
  34. bool vis[];
  35.  
  36. ll Hash(int *t){
  37. ll tem = , ans = ;
  38. for(int i = ; i < ; i++){
  39. ans += tem * t[i];
  40. tem *= ;
  41. }
  42. return ans;
  43. }
  44.  
  45. int stack[], k2;
  46. ll states[];
  47. int ks;
  48. int table[][];
  49.  
  50. void dfs(ll num, int limit, int next){
  51. if(next){
  52. memcpy(buf, stack, sizeof buf);
  53. sort(buf, buf + , cmp);
  54. ll hash_value = Hash(buf);
  55. states[ks++] = hash_value;
  56. memcpy(table[ks - ], buf, sizeof buf);
  57. mapi[hash_value] = ks - ;
  58. }
  59. if(next > ) return;
  60. for(int i = ; i <= limit; i++){
  61. num *= a[next];
  62. if(num > S) break;
  63. stack[k2++] = i;
  64. dfs(num, i, next + );
  65. stack[--k2] = ;
  66. }
  67. }
  68.  
  69. void shaffix(){
  70. bool vis[ + ];
  71. int mid = (int)5e5 + ;
  72. cls(vis, );
  73. for(int i = ; i < mid; i++){
  74. if(vis[i]) continue;
  75. prime[k++] = i;
  76. for(ll j = (ll)i * ; j < mid; j += i) vis[j] = ;
  77. }
  78. }
  79.  
  80. void cal(int id);
  81.  
  82. void dfs1(int id, int next){
  83. if(next > ){
  84. int buf1[], buf2[];
  85. memcpy(buf1, stack, sizeof stack);
  86. for(int i = ; i < ; i++) buf2[i] = table[id][i] - buf1[i];
  87. sort(buf1, buf1 + , cmp);
  88. sort(buf2, buf2 + , cmp);
  89. if(!buf1[] || !buf2[]) return;
  90. ll hash_value1 = Hash(buf1), hash_value2 = Hash(buf2);
  91. int id1 = mapi[hash_value1], id2 = mapi[hash_value2];
  92. cal(id1), cal(id2);
  93. double prefix_left = , prefix_right = ;
  94. for(int i = ; i < ; i++){
  95. dp[id][i + ] += dp[id1][i] * prefix_right +
  96. prefix_left * dp[id2][i] + dp[id1][i] * dp[id2][i];
  97. prefix_left += dp[id1][i], prefix_right += dp[id2][i];
  98. }
  99. return;
  100. }
  101. for(int i = ; i <= table[id][next]; i++){
  102. stack[k2++] = i;
  103. dfs1(id, next + );
  104. stack[--k2] = ;
  105. }
  106. }
  107.  
  108. void cal(int id){
  109. if(vis[id]) return;
  110. k2 = ;
  111. dfs1(id, );
  112. int sum = ;
  113. for(int i = ; i < ; i++) sum *= + table[id][i];
  114. sum -= ;
  115. for(int i = ; i < ; i++) dp[id][i] /= sum;
  116. vis[id] = ;
  117. //printf("%d+\n", id);
  118. }
  119.  
  120. void init(){
  121. shaffix();
  122. cls(vis, );
  123. vis[] = ;
  124. mapi.clear();
  125. //0...10 < 10^11
  126. cls(stack, );
  127. ks = k2 = ;
  128. dfs(, , );
  129. cls(dp, );
  130. dp[][] = ;
  131. for(int i = ; i < ks; i++) cal(i);
  132. }
  133.  
  134. double solve(ll num){
  135. cls(buf, );
  136. k1 = ;
  137. int mid = (int)sqrt((double)num);
  138. for(int i = ; i < k && prime[i] <= mid; i++){
  139. if(num % prime[i]) continue;
  140. while(num % prime[i] == ) ++buf[k1], num /= prime[i];
  141. mid = (int)sqrt((double)num);
  142. k1++;
  143. }
  144. if(num != ) buf[k1++] = ;
  145. sort(buf, buf + , cmp);
  146. ll hash_value = Hash(buf);
  147. double ans = ;
  148. int id = mapi[hash_value];
  149. for(int i = ; i < ; i++) ans += dp[id][i] * i;
  150. return ans;
  151. }
  152.  
  153. int main(){
  154. //freopen("in.txt", "r", stdin);
  155. //freopen("out.txt", "w", stdout);
  156. int T, kase = ;
  157. init();
  158. scanf("%d", &T);
  159. ll n;
  160. while(T--){
  161. scanf("%I64d", &n);
  162. double ans = solve(n);
  163. printf("Case #%d: %.6f\n", ++kase, ans);
  164. }
  165. return ;
  166. }

hdu4935 Prime Tree(2014多校联合第七场)的更多相关文章

  1. hdu4940 Destroy Transportation system(2014多校联合第七场)

    题意很容易转化到这样的问题:在一个强连通的有向图D中是否存在这样的集合划分S + T = D,从S到T集合的边权大于从T到S集合的边权. 即D(i, j)  > B(j, i) + D(j, i ...

  2. HDU 4869 Turn the pokers (2014多校联合训练第一场1009) 解题报告(维护区间 + 组合数)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  3. hdu5379||2015多校联合第7场1011 树形统计

    pid=5379">http://acm.hdu.edu.cn/showproblem.php? pid=5379 Problem Description Little sun is ...

  4. 2014 多校联合训练赛6 Fighting the Landlords

    本场比赛的三个水题之一,题意是两个玩家每人都持有一手牌,问第一个玩家是否有一种出牌方法使得在第一回和对方无牌可出.直接模拟即可,注意一次出完的情况,一开始没主意,wa了一发. #include< ...

  5. hdu 4869 Turn the pokers (2014多校联合第一场 I)

    Turn the pokers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. HDU 4870 Rating (2014 多校联合第一场 J)(概率)

    题意: 一个人有两个TC的账号,一开始两个账号rating都是0,然后每次它会选择里面rating较小的一个账号去打比赛,每次比赛有p的概率+1分,有1-p的概率-2分,当然如果本身是<=2分的 ...

  7. HDU 4893 Wow! Such Sequence!(2014年多校联合 第三场 G)(线段树)

    磨了一天的线段树,不能说完全搞清楚,只能说有一个大概的了解,靠着模板才把这道题A了,只能说太弱~~! 题意: 初始时有一字符串,全为0. 三种操作: 1 k d - add  把d加到第k个数上去2 ...

  8. HDU 4869 Turn the pokers (2014 多校联合第一场 I)

    HDOJ--4869--Turn the pokers[组合数学+快速幂] 题意:有m张扑克,开始时全部正面朝下,你可以翻n次牌,每次可以翻xi张,翻拍规则就是正面朝下变背面朝下,反之亦然,问经过n次 ...

  9. HDU 4865 Peter's Hobby(2014 多校联合第一场 E)(概率dp)

    题意:已知昨天天气与今天天气状况的概率关系(wePro),和今天天气状态和叶子湿度的概率关系(lePro)第一天为sunny 概率为 0.63,cloudy 概率 0.17,rainny 概率 0.2 ...

随机推荐

  1. Eclipse 调试 Java 程序的技巧

    - 断点视图 : 条件断点 如果你只对应用中的某部分感兴趣的话,这个功能非常有用.例如,如果你要在第13次循环的时候检查程序,或者在一个抽象父类中调试某些功能,而你只关注其中一个具体的实现.你可以在断 ...

  2. 生成arff文件,csv转为arff

    一.什么是arff格式文件 1.arff是Attribute-Relation File Format缩写,从英文字面也能大概看出什么意思.它是weka数据挖掘开源程序使用的一种文件模式.由于weka ...

  3. AXIS2调用web service,返回结果用GZIP解压缩

    import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOExceptio ...

  4. c语言的基本语法

    1. 二目运算符从右往左 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右   () 圆括号 (表达式)/函数名(形参表)   . 成员选择(对象 ...

  5. hdu 4998

    http://acm.hdu.edu.cn/showproblem.php?pid=4998 这道题,在比赛的时候看了很久,才明白题目的大意.都怪自己不好好学习英语.后来经过队友翻译才懂是什么意思. ...

  6. [Reprint]C++普通函数指针与成员函数指针实例解析

    这篇文章主要介绍了C++普通函数指针与成员函数指针,很重要的知识点,需要的朋友可以参考下   C++的函数指针(function pointer)是通过指向函数的指针间接调用函数.相信很多人对指向一般 ...

  7. Python基础(1)python+Eclipse+pydev环境搭建

    编辑器:Python 自带的 IDLE 简单快捷, 学习Python或者编写小型软件的时候.非常有用.         编辑器: Eclipse + pydev插件 1. Eclipse是写JAVA的 ...

  8. oracle安装过程中遇到的问题

    今天遭遇ORA-12560: TNS: 协议适配器错误的问题,经过一番努力问题已经解决,与大家共享. 造成ORA-12560: TNS: 协议适配器错误的问题的原因有三个: 1.监听服务没有起起来.w ...

  9. CentOs5.2中PHP的升级

    最近一个项目中需要使用到PHP5.2的版本,而服务器上使用了官方的yum源进行安装,默认的版本是5.1.6,需要升级.但是因为不是一个非常 正式的服务器环境,所以想通过简单的yum update一下了 ...

  10. 如何学习c++

    在之后的随笔中,我作为一个c++的初学者将会把我如何学习c++的经历尽可能详细的记录下来. 这里引用了JerryZhang在他的博文里面写的一段话,当作我的座右铭. 1.多交流:不管你的技术多么硬,你 ...