题目描述

给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?

输入

第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

输出

一个整数,表示不同的满足要求的树的个数,无解输出0

样例输入

3
1
-1
-1

样例输出

2


题解

Prufer序列+高精度

Prufer序列:由一棵 $n$ 个点的树唯一产生的一个 $n-2$ 个数的序列。

生成方法:找到这棵树编号最小的叶子节点,将其相邻点加入到序列中,删掉这个点。重复这个过程直到树中只剩下两个点,此时得到的序列即为该树的Prufer序列。

性质:任何一个长度为 $n-2$ ,每个数均在 $1\sum n$ 之间的序列均为一个合法的Prufer序列,对应且只对应着一棵 $n$ 个点的树。

性质:在原树中度数为 $d$ 的点,在Prufer序列中出现了 $d-1$ 次。

根据这两个性质可以考虑本题。给出了每个点的度数限制,即给出了每个点在Prufer序列中出现的次数。对于没给限制的,可以随意选择。

相当于先在 $n-2$ 个数中选出一部分作为没有限制的,剩下的是有限制的。

对于没有限制的,答案就是 $没限制的位置个数^没限制的点的个数$ 。

对于有限制的,使用组合数学的一个公式:长度为 $\sum a_i$ 的序列,第 $i$ 个数出现了 $a_i$ 次的序列数为 $\frac{(\sum a_i)!}{\prod(a_i!)}$ 。

本题不取模,为避免高精度除法,将阶乘分解质因数来处理。

注意特判无解的情况。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define mod 100000000
  5. using namespace std;
  6. typedef long long ll;
  7. struct data
  8. {
  9. int len;
  10. ll v[400];
  11. ll &operator[](int a) {return v[a];}
  12. data operator+(data &a)
  13. {
  14. data ans;
  15. memset(ans.v , 0 , sizeof(ans.v));
  16. int i;
  17. for(i = 0 ; i < len || i < a.len || ans[i] ; i ++ )
  18. ans[i] += v[i] + a[i] , ans[i + 1] = ans[i] / mod , ans[i] %= mod;
  19. ans.len = i;
  20. return ans;
  21. }
  22. data operator*(int a)
  23. {
  24. data ans;
  25. memset(ans.v , 0 , sizeof(ans.v));
  26. int i;
  27. for(i = 0 ; i < len || ans[i] ; i ++ )
  28. ans[i] += v[i] * a , ans[i + 1] = ans[i] / mod , ans[i] %= mod;
  29. ans.len = i;
  30. return ans;
  31. }
  32. void write()
  33. {
  34. int i;
  35. printf("%lld" , v[len - 1]);
  36. for(i = len - 2 ; ~i ; i -- ) printf("%08lld" , v[i]);
  37. puts("");
  38. }
  39. }ans;
  40. int a[1010] , cnt[1010] , prime[1010] , tot , np[1010];
  41. void init()
  42. {
  43. int i , j;
  44. for(i = 2 ; i <= 1000 ; i ++ )
  45. {
  46. if(!np[i]) prime[++tot] = i;
  47. for(j = 1 ; j <= tot && i * prime[j] <= 1000 ; j ++ )
  48. {
  49. np[i * prime[j]] = 1;
  50. if(i % prime[j] == 0) break;
  51. }
  52. }
  53. }
  54. void solve(int x , int a)
  55. {
  56. int i , j;
  57. for(i = 1 ; i <= tot ; i ++ )
  58. for(j = x / prime[i] ; j ; j /= prime[i])
  59. cnt[i] += a * j;
  60. }
  61. int main()
  62. {
  63. init();
  64. int n , i , c1 = 0 , c2 = 0;
  65. scanf("%d" , &n);
  66. for(i = 1 ; i <= n ; i ++ )
  67. {
  68. scanf("%d" , &a[i]);
  69. if(a[i] > 0) c1 += a[i] - 1;
  70. else if(a[i] == -1) c2 ++ ;
  71. else
  72. {
  73. puts("0");
  74. return 0;
  75. }
  76. }
  77. if(c1 > n - 2)
  78. {
  79. puts("0");
  80. return 0;
  81. }
  82. solve(n - 2 , 1) , solve(n - 2 - c1 , -1);
  83. for(i = 1 ; i <= n ; i ++ )
  84. if(a[i] > 0)
  85. solve(a[i] - 1 , -1);
  86. ans[0] = ans.len = 1;
  87. for(i = 1 ; i <= tot ; i ++ )
  88. while(cnt[i] -- )
  89. ans = ans * prime[i];
  90. for(i = 1 ; i <= n - 2 - c1 ; i ++ ) ans = ans * c2;
  91. ans.write();
  92. return 0;
  93. }

【bzoj1005】[HNOI2008]明明的烦恼 Prufer序列+高精度的更多相关文章

  1. bzoj1005: [HNOI2008]明明的烦恼 prufer序列

    https://www.lydsy.com/JudgeOnline/problem.php?id=1005 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的 ...

  2. [bzoj1005][HNOI2008]明明的烦恼-Prufer编码+高精度

    Brief Description 给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多少棵度数满足要求的树? Algorithm Design 结论题. 首先可以参考这篇文章 ...

  3. BZOJ 1005 明明的烦恼(prufer序列+高精度)

    有一种东西叫树的prufer序列,一个树的与一个prufer序列是一一对应的关系. 设有m个度数确定的点,这些点的度为dee[i],那么每个点在prufer序列中出现了dee[i]-1次. 由排列组合 ...

  4. [BZOJ1005] [HNOI2008] 明明的烦恼 (prufer编码)

    Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N ...

  5. bzoj1005: [HNOI2008]明明的烦恼(prufer+高精度)

    1005: [HNOI2008]明明的烦恼 题目:传送门 题解: 毒瘤题啊天~ 其实思考的过程还是比较简单的... 首先当然还是要了解好prufer序列的基本性质啦 那么和1211大体一致,主要还是利 ...

  6. BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5786  Solved: 2263[Submit][Stat ...

  7. bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&&生成树计数

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Statu ...

  8. bzoj1005 [HNOI2008]明明的烦恼

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3032  Solved: 1209 Description ...

  9. BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数

    1005: [HNOI2008]明明的烦恼 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...

随机推荐

  1. 我们一起学习WCF 第八篇回调函数

    什么是回调函数? 一个简单的例子:小明想要在京东购买一件商品.他会登陆网站选好自己的商品.然后他把这件商品放在购物车,然后开始付钱(这个表示触发,不付钱不发货(排除货到付款)).然后京东的人员收到了小 ...

  2. Linux安装JDK8详细步骤

    1.下载jdk8 查看Linux位数,到oracle官网下载对应的jdk ① sudo uname --m  确认32位还是64位 ② https://www.oracle.com/technetwo ...

  3. “错误: 编码GBK的不可映射字符” 的解决方案

    命令行下,用javac命令编译java程序时,如果文档的编码为“utf-8”,并且含有中文字符时,会出现乱码现象,编译通过不了.如图: 解决方案:编译时指定编码方式,防止乱码.如下:

  4. OpenLDAP介绍

    首先LDAP是一个轻量级的产品(LightWeight),是一个Directory(D),存取的协议(Access Protocol). 我要着重指出,LDAP是一个数据库,但是又不是一个数据库.说他 ...

  5. RC电路简介,RC串并联电路的工作原理及应用

    RC电路简介,RC串并联电路的工作原理及应用 RC电路全称Resistance-Capacitance Circuits.一个 相移电路(RC电路)或称 RC滤波器. RC网络, 是一个包含利用电压源 ...

  6. NodeJS实现同步的方法

    NodeJS被打上了单线程.非阻塞.事件驱动…..等标签. 在单线程的情况下,是无法开启子线程的.经过了很久的研究,发现并没有thread函数!!!但是有时候,我们确实需要“多线程”处理事务.node ...

  7. Serverless 架构的优点和缺点

    Serverless 的优势 在我使用 Serverless Framework 开发 AWS Serverless 应用的过程中,最方便的莫过于,第一次部署和第二次.第三次部署没有什么区别.只需要执 ...

  8. Chrome 鲜为人知的秘籍(内部协议)&&Chrome功能指令大全

    楼主以 Chrome 版本 39.0.2171.95 m 为例,耗费2小时的记录: chrome://accessibility 用于查看浏览器当前访问的标签,打开全局访问模式可以查看:各个标签页面的 ...

  9. 2018-2019-20172321 《Java软件结构与数据结构》第四周学习总结

    2018-2019-20172321 <Java软件结构与数据结构>第四周学习总结 教材学习内容总结 第六章 6.1列表集合 列表集合是一种概念性表示法,其思想是使事物以线性列表的方式进行 ...

  10. 《JavaScript》JavaScript的名字和版本

    语言标准版本名字:ECMAScript(ECMA是欧洲计算机制造协会,据说可能是专门做标准的,除了JavaScript遵循这个标准以外,还有XX....)    Jscript(IE对该语言实现版本的 ...