[bzoj1005] [洛谷P2624] 明明的烦恼
###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)^
$
注意要高精度
##代码##
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1005;
const int SZ = 1000;
int n;
int d[N];
struct Bint{
int a[N];
int s;
Bint operator * (const int &b) const{
Bint c;
int g=0,f;
for(int i=0;i<s;i++){
f=g+a[i]*b;
c.a[i]=f%SZ;
g=f/SZ;
}
if(g) c.a[s]=g,c.s=s+1;
else c.s=s;
return c;
}
Bint operator / (const int &b) const{
Bint c;
int g=0,f;
for(int i=s-1;i>=0;i--){
f=g*SZ+a[i];
c.a[i]=f/b;
g=f%b;
}
c.s=s;
while(c.s && c.a[c.s-1]==0) c.s--;
return c;
}
Bint operator *= (const int &b) { return *this=*this*b; }
Bint operator /= (const int &b) { return *this=*this/b; }
void output(){ //注意
printf("%d",a[s-1]);
for(int i=s-2;i>=0;i--) {
if(a[i]==0) printf("000");
else if(a[i]<10) printf("00%d",a[i]);
else if(a[i]<100) printf("0%d",a[i]);
else printf("%d",a[i]);
}
printf("\n");
}
}ans;
int main()
{
int s=0,m=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&d[i]);
if(d[i]!=-1) m++,s+=d[i]-1;
}
ans.a[0]=1; ans.s=1;
for(int i=n-s-1;i<=n-2;i++) ans*=i;
for(int i=1;i<=n;i++) if(d[i]>1) {
for(int j=2;j<=d[i]-1;j++) ans/=j;
}
for(int i=0;i<n-s-2;i++) ans*=(n-m);
ans.output();
return 0;
}
另一种高精度写法(本质无区别,只是几个月后的写法) 【捂脸】
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1005;
int n,d[N];
struct Bign{
int s[3*N],l;
Bign() { memset(s,0,sizeof(s)); l=0; }
}ans;
Bign mul(Bign a,int x){
Bign c;
for(int i=0,g=0;;i++){
if(i>=a.l && g==0) { c.l=i; break; }
c.s[i]=(a.s[i]*x+g)%10;
g=(a.s[i]*x+g)/10;
}
return c;
}
Bign div(Bign a,int x){
Bign c;
c.l=a.l;
for(int i=a.l-1,g=0;i>=0;i--){
g=g*10+a.s[i];
c.s[i]=g/x;
g=g%x;
}
while(c.l && c.s[c.l-1]==0) c.l--;
return c;
}
void output(Bign a){
for(int i=a.l-1;i>=0;i--)
printf("%d",a.s[i]);
printf("\n");
}
int main()
{
int m,t=0;
scanf("%d",&n);
m=n-2;
for(int i=1;i<=n;i++) {
scanf("%d",&d[i]);
if(d[i]==-1) t++;
else m-=(d[i]-1);
}
ans.s[ans.l++]=1;
for(int i=m+1;i<=n-2;i++) ans=mul(ans,i);
for(int i=1;i<=n;i++)
for(int j=2;j<d[i];j++) ans=div(ans,j);
for(int i=1;i<=m;i++) ans=mul(ans,t);
output(ans);
return 0;
}
[bzoj1005] [洛谷P2624] 明明的烦恼的更多相关文章
- 2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?)
2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?) [P2624 HNOI2008]明明的烦恼 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn ...
- 【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度
[BZOJ1005][HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可 ...
- 【洛谷P1059 明明的随机数】
题目描述明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着 ...
- 洛谷 P1059 明明的随机数
题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了NNN个111到100010001000之间的随机整数(N≤100)(N≤100)(N≤100),对于其中重复 ...
- 洛谷 P1059明明的随机数 & P1068分数线划定 & P1781宇宙总统
题目:https://www.luogu.org/problemnew/show/P1059 思路:STL中的set使用. //#include<bits/stdc++.h> #inclu ...
- 【洛谷2624】[HNOI2008] 明明的烦恼(Python+利用prufer序列结论求解)
点此看题面 大致题意: 给你某些点的度数,其余点度数任意,让你求有多少种符合条件的无根树. \(prufer\)序列 一道弱化版的题目:[洛谷2290][HNOI2004] 树的计数. 这同样也是一道 ...
- 【洛谷2624_BZOJ1005】[HNOI2008] 明明的烦恼(Prufer序列_高精度_组合数学)
题目: 洛谷2624 分析: 本文中所有的 "树" 都是带标号的. 介绍一种把树变成一个序列的工具:Prufer 序列. 对于一棵 \(n\) 个结点的树,每次选出一个叶子(度数为 ...
- 【BZOJ1005】[HNOI2008]明明的烦恼(prufer序列)
[BZOJ1005][HNOI2008]明明的烦恼(prufer序列) 题面 BZOJ 洛谷 题解 戳这里 #include<iostream> #include<cstdio> ...
- 「BZOJ1005」[HNOI2008] 明明的烦恼
「BZOJ1005」[HNOI2008] 明明的烦恼 先放几个prufer序列的结论: Prufer序列是一种对有标号无根树的编码,长度为节点数-2. 具体存在无根树转化为prufer序列和prufe ...
随机推荐
- Codevs 四子连棋 (迭代加深搜索)
题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双 ...
- 给培训学校讲解ORM框架的课件
导读:这是我给某培训学校培训.net程序员所设计的课件,他们普遍反映太难了,是这样吗?
- C# 如何写出一个不能被其他程序集继承的抽象类
我需要限定某个抽象类只能在我程序集类实现,而不支持其他程序集实现,也就是我需要一个不能被继承的抽象类 在 C# 里面有抽象类和接口,这两个都是期望被继承才能被使用,而抽象类是可以做到只能在自己程序集和 ...
- 【51.64%】【POJ 1330】Nearest Common Ancestors
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 26416 Accepted: 13641 Description A roote ...
- C++Review7_STL、容器、迭代器
我之前的博文中有专门的5篇整理并介绍了STL的概念: STL1——整体介绍:https://www.cnblogs.com/grooovvve/p/10467794.html STL2——泛型编程(模 ...
- JAVA8学习——深入浅出Lambda表达式(学习过程)
JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...
- 聊聊多线程哪一些事儿(task)之 三 异步取消和异步方法
hello,咋们又见面啦,通过前面两篇文章的介绍,对task的创建.运行.阻塞.同步.延续操作等都有了很好的认识和使用,结合实际的场景介绍,这样一来在实际的工作中也能够解决很大一部分的关于多线程的业务 ...
- 阿里面试官让我讲讲Unicode,我讲了3秒说没了,面试官说你可真菜
本文首发于微信公众号:程序员乔戈里 乔哥:首先说说什么是Unicode.码点吧~要想搞懂,这些概念必须清楚 什么是Unicode? 下图来自http://www.unicode.org/standar ...
- The sixth day of Crawler learning
爬取我爱竞赛网的大量数据 首先获取每一种比赛信息的分类链接 def get_type_url(url): web_data = requests.get(web_url) soup = B ...
- 20191010-7 alpha week 1/2 Scrum立会报告+燃尽图 06
此作业参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/8750 小组名称:“组长”组 组长:杨天宇 组员:魏新,罗杨美慧,王歆瑶,徐丽 ...