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

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

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

###Sample Input###
3
1

-1

###Sample Output###
2

###HINT###

两棵树分别为1-2-3;1-3-2


##想法##

这道题用了一个叫做prufer编码的东西(新技能get)

首先prufer编码是啥呢?
引用一下怡红公子的话:

该题运用到了树的prufer编码的性质:
(1)树的prufer编码的实现
不断 删除树中度数为1的最小序号的点,并输出与其相连的节点的序号 直至树中只有两个节点
(2)通过观察我们可以发现
任意一棵n节点的树都可唯一的用长度为n-2的prufer编码表示
度数为m的节点的序号在prufer编码中出现的次数为m-1
(3)怎样将prufer编码还原为一棵树??
从prufer编码的最前端开始扫描节点,设该节点序号为 u ,寻找不在prufer编码的最小序号且没有被标记的节点 v ,连接 u,v,并标记v,将u从prufer编码中删除。扫描下一节点。

这个东西自己画一下挺好理解的。

感觉它最神奇的一点就是这n-2位的编码可以随便填,没有特殊的限制,一个编码就能对应一棵树
一开始我想的是现在n个点中选一个点当根,然后剩余n-1个点都选一个自己的父节点,根据度数判断这个点是多少个点的父节点,但这样有一些问题,比如可能出现环。
而prufer编码就不会出现这样的问题了。

如果我们知道了每个点的度数d[i]
那么满足的树的个数(即prufer编码个数)为 \(\frac{(n-2)!}{\prod(d[i]-1)!}\)
但是题目中有一些点的度数是不知道的。设知道度数的点有m个,它们的 \(\sum d[i]-1\) 为s
那么满足的树的个数为
$
\frac{s!}{\prod(d[i]-1)!} \times C_s \times (n-m) \
=\frac{(n-2)!}{\prod(d[i]-1)! \times (n-2-s)!} \times (n-m)^
$
注意要高精度


##代码##

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N = 1005;
  6. const int SZ = 1000;
  7. int n;
  8. int d[N];
  9. struct Bint{
  10. int a[N];
  11. int s;
  12. Bint operator * (const int &b) const{
  13. Bint c;
  14. int g=0,f;
  15. for(int i=0;i<s;i++){
  16. f=g+a[i]*b;
  17. c.a[i]=f%SZ;
  18. g=f/SZ;
  19. }
  20. if(g) c.a[s]=g,c.s=s+1;
  21. else c.s=s;
  22. return c;
  23. }
  24. Bint operator / (const int &b) const{
  25. Bint c;
  26. int g=0,f;
  27. for(int i=s-1;i>=0;i--){
  28. f=g*SZ+a[i];
  29. c.a[i]=f/b;
  30. g=f%b;
  31. }
  32. c.s=s;
  33. while(c.s && c.a[c.s-1]==0) c.s--;
  34. return c;
  35. }
  36. Bint operator *= (const int &b) { return *this=*this*b; }
  37. Bint operator /= (const int &b) { return *this=*this/b; }
  38. void output(){ //注意
  39. printf("%d",a[s-1]);
  40. for(int i=s-2;i>=0;i--) {
  41. if(a[i]==0) printf("000");
  42. else if(a[i]<10) printf("00%d",a[i]);
  43. else if(a[i]<100) printf("0%d",a[i]);
  44. else printf("%d",a[i]);
  45. }
  46. printf("\n");
  47. }
  48. }ans;
  49. int main()
  50. {
  51. int s=0,m=0;
  52. scanf("%d",&n);
  53. for(int i=1;i<=n;i++){
  54. scanf("%d",&d[i]);
  55. if(d[i]!=-1) m++,s+=d[i]-1;
  56. }
  57. ans.a[0]=1; ans.s=1;
  58. for(int i=n-s-1;i<=n-2;i++) ans*=i;
  59. for(int i=1;i<=n;i++) if(d[i]>1) {
  60. for(int j=2;j<=d[i]-1;j++) ans/=j;
  61. }
  62. for(int i=0;i<n-s-2;i++) ans*=(n-m);
  63. ans.output();
  64. return 0;
  65. }

另一种高精度写法(本质无区别,只是几个月后的写法) 【捂脸】

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cstring>
  5. using namespace std;
  6. const int N = 1005;
  7. int n,d[N];
  8. struct Bign{
  9. int s[3*N],l;
  10. Bign() { memset(s,0,sizeof(s)); l=0; }
  11. }ans;
  12. Bign mul(Bign a,int x){
  13. Bign c;
  14. for(int i=0,g=0;;i++){
  15. if(i>=a.l && g==0) { c.l=i; break; }
  16. c.s[i]=(a.s[i]*x+g)%10;
  17. g=(a.s[i]*x+g)/10;
  18. }
  19. return c;
  20. }
  21. Bign div(Bign a,int x){
  22. Bign c;
  23. c.l=a.l;
  24. for(int i=a.l-1,g=0;i>=0;i--){
  25. g=g*10+a.s[i];
  26. c.s[i]=g/x;
  27. g=g%x;
  28. }
  29. while(c.l && c.s[c.l-1]==0) c.l--;
  30. return c;
  31. }
  32. void output(Bign a){
  33. for(int i=a.l-1;i>=0;i--)
  34. printf("%d",a.s[i]);
  35. printf("\n");
  36. }
  37. int main()
  38. {
  39. int m,t=0;
  40. scanf("%d",&n);
  41. m=n-2;
  42. for(int i=1;i<=n;i++) {
  43. scanf("%d",&d[i]);
  44. if(d[i]==-1) t++;
  45. else m-=(d[i]-1);
  46. }
  47. ans.s[ans.l++]=1;
  48. for(int i=m+1;i<=n-2;i++) ans=mul(ans,i);
  49. for(int i=1;i<=n;i++)
  50. for(int j=2;j<d[i];j++) ans=div(ans,j);
  51. for(int i=1;i<=m;i++) ans=mul(ans,t);
  52. output(ans);
  53. return 0;
  54. }

[bzoj1005] [洛谷P2624] 明明的烦恼的更多相关文章

  1. 2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?)

    2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?) [P2624 HNOI2008]明明的烦恼 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn ...

  2. 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度

    [BZOJ1005][HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可 ...

  3. 【洛谷P1059 明明的随机数】

    题目描述明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着 ...

  4. 洛谷 P1059 明明的随机数

    题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了NNN个111到100010001000之间的随机整数(N≤100)(N≤100)(N≤100),对于其中重复 ...

  5. 洛谷 P1059明明的随机数 & P1068分数线划定 & P1781宇宙总统

    题目:https://www.luogu.org/problemnew/show/P1059 思路:STL中的set使用. //#include<bits/stdc++.h> #inclu ...

  6. 【洛谷2624】[HNOI2008] 明明的烦恼(Python+利用prufer序列结论求解)

    点此看题面 大致题意: 给你某些点的度数,其余点度数任意,让你求有多少种符合条件的无根树. \(prufer\)序列 一道弱化版的题目:[洛谷2290][HNOI2004] 树的计数. 这同样也是一道 ...

  7. 【洛谷2624_BZOJ1005】[HNOI2008] 明明的烦恼(Prufer序列_高精度_组合数学)

    题目: 洛谷2624 分析: 本文中所有的 "树" 都是带标号的. 介绍一种把树变成一个序列的工具:Prufer 序列. 对于一棵 \(n\) 个结点的树,每次选出一个叶子(度数为 ...

  8. 【BZOJ1005】[HNOI2008]明明的烦恼(prufer序列)

    [BZOJ1005][HNOI2008]明明的烦恼(prufer序列) 题面 BZOJ 洛谷 题解 戳这里 #include<iostream> #include<cstdio> ...

  9. 「BZOJ1005」[HNOI2008] 明明的烦恼

    「BZOJ1005」[HNOI2008] 明明的烦恼 先放几个prufer序列的结论: Prufer序列是一种对有标号无根树的编码,长度为节点数-2. 具体存在无根树转化为prufer序列和prufe ...

随机推荐

  1. 2019.12.15 QLU and SNDU期末联赛

    题目列表: 1582.柳予欣的舔狗行为 1587.柳予欣的女朋友们在分享水果 1585.柳予欣和她女朋友的购物计划 1579.FFFFFunctions 1588.Zeckendorf 1586.柳予 ...

  2. 测试驱动开发实践—从testList开始

    [内容指引]运行单元测试:装配一条数据:模拟更多数据测试列表:测试无搜索列表:测试标准查询:测试高级查询. 一.运行单元测试 我们以文档分类(Category)这个领域类为例,示范如何通过编写测试用例 ...

  3. video视频标签一些设置,包括封面、播放结束后的封面、视频占满屏幕的方式、视频播放暂停、展示控制栏、触发全屏播放事件

    video视频标签一些设置,包括封面.播放结束后的封面.视频占满屏幕的方式.视频链接.视频播放暂停.展示控制栏.触发全屏播放事件 <video id="video" auto ...

  4. 【37.48%】【hdu 2587】How far away ?(3篇文章,3种做法,LCA之树上倍增)

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

  5. HBase 分裂(split)

    1. 为什么split 最初一个Table 只有一个region(因此只能存放在一个region server上).随着数据的不断写入,HRegion越来越大,当到达一定程度后分裂为两个,通过负载均衡 ...

  6. 0009 CSS基础选择器( 标签、类、id、通配符)

    typora-copy-images-to: media 第01阶段.前端基础.CSS基础选择器 CSS选择器(重点) 学习目标: 理解 能说出选择器的作用 id选择器和类选择器的区别 应用 能够使用 ...

  7. HTTP中GET与POST的区别 99%的错误认识

    @[TOC本篇文章分两部分,第一部分可以列为初为新人的装逼失败模式,第二部分列为修炼低调模式. 装逼失败模式:99%的人对GET和POST的认识 修炼低调模式:1%不知道的进阶认识 GET和POST, ...

  8. DEVOPS技术实践_03:Jenkins自动构建

    一.提交代码自动构建 当开发人员在gitlab提交代码后,会自动触发jenkin构建 点击项目---->点击diy_maven-TEST----->点击配置--->构建触发器---- ...

  9. [工具] Git版本管理(一)(基本操作)

    一.版本控制的发展 1.用文件来做版本控制 我们在写论文.做方案等的时候,一般都会同时在文件夹中存在很多版本的文件. 例如: 这种方式很常用,在很多领域都是用这种方式来进行版本控制的. 2.本地版本控 ...

  10. Java高级特性——流

    以上就是这段时间学习完流的知识以后我的总结,.mmap文件可以去我的github上获取:https://github.com/xiaozhengyu/StudyNotes.git