1211: [HNOI2004]树的计数

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3432  Solved: 1295
[Submit][Status][Discuss]

Description

一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵。给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di的树的个数。

Input

第一行是一个正整数n,表示树有n个结点。第二行有n个数,第i个数表示di,即树的第i个结点的度数。其中1<=n<=150,输入数据保证满足条件的树不超过10^17个。

Output

输出满足条件的树有多少棵。

Sample Input

4
2 1 2 1

Sample Output

2
 
 
 

先丟几个Prufer序列的性质:

1.与无根树一一对应。

2.度数为$d_i$的点会在Prufer序列中出现$d_i-1$次。

3.一个$n$个节点的完全图的生成树个数为$n^{n-2}$

  解释一下:prufer序列长为$n-2$,每个位置有$n$种可能性。

4.对于给定每个点度数的无根树,共有$\frac{(n-2)!}{\prod \limits _{i=1}^n {(d_i-1)!}}$种情况。

  其实就是$d_i-1$个$i$的可重全排列。

那么这道题就用上面这个结论切掉就好了。求组合数直接分解质因数,记得要特判$n==1$及不联通的情况。

#include<cstdio>
#include<iostream>
#include<cstring>
const int N=;
int d[N],n;
int vis[N],pri[N],res[N],tot,sum,ans[N*],bu[N];
void getprime()
{
for(int i=;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,res[i]=tot;
for(int j=;j<=tot;j++)
{
if(pri[j]*i>n)break;
vis[i*pri[j]]=;res[i*pri[j]]=j;
if(i%pri[j]==)break;
}
}
}
void divi(int x,int val)
{
while(x!=)bu[res[x]]+=val,x/=pri[res[x]];
}
void mult(int a[],int x)
{
int k=;
for(int i=;i<=a[];i++)
{
int tmp=a[i]*x+k;
a[i]=tmp%;
k=tmp/;
}
while(k)a[++a[]]=k%,k/=;
}
int main()
{
scanf("%d",&n);
if(n==)
{
int deg;
scanf("%d",&deg);
if(!deg)puts("");
else puts("");
return ;
}
getprime();
for(int i=;i<=n;i++)
{
scanf("%d",&d[i]);
if(!d[i])
{
puts("");
return ;
}
sum+=d[i]-;
}
if(sum!=n-)
{
puts("");
return ;
}
for(int i=n-;i>=;i--)
divi(i,);
for(int i=;i<=n;i++)
{
for(int j=d[i]-;j>=;j--)
divi(j,-);
}
ans[]=ans[]=;
for(int i=;i<=tot;i++)
while(bu[i]--)mult(ans,pri[i]);
for(int i=ans[];i;i--)
printf("%d",ans[i]);
return ;
}

1005: [HNOI2008]明明的烦恼

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7125  Solved: 2818
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

3
1
-1
-1

Sample Output

2

HINT

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

本题的问题在于有的点度数是不确定的。

所以我们先求出$sum=\sum d_i-1$,之后从总长度$n-2$中选出这些

对于剩下的不确定度数的部分,我们设已知度数点的个数为$cnt$

那么现在有$n-2-sum$个位置可以任意排列$n-cnt$个点

易得最终答案为

$C_{n-2}^{sum}*\frac{(n-2)!}{\prod \limits _{i=1}^{cnt} {(d_i-1)!}}*(n-cnt)^{n-2-sum}$

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=;
int d[N],n;
int vis[N],pri[N],res[N],tot,sum,cnt,ans[N*],bu[N];
void getprime()
{
for(int i=;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,res[i]=tot;
for(int j=;j<=tot;j++)
{
if(pri[j]*i>n)break;
vis[i*pri[j]]=;res[i*pri[j]]=j;
if(i%pri[j]==)break;
}
}
}
void divi(int x,int val)
{
while(x!=)bu[res[x]]+=val,x/=pri[res[x]];
}
void mult(int a[],int x)
{
int k=;
for(int i=;i<=a[];i++)
{
int tmp=a[i]*x+k;
a[i]=tmp%;
k=tmp/;
}
while(k)a[++a[]]=k%,k/=;
} int main()
{
scanf("%d",&n);
getprime();
for(int i=;i<=n;i++)
{
scanf("%d",&d[i]);
if(d[i]!=-)sum+=d[i]-,cnt++;
}
for(int i=n-;i>=;i--)
divi(i,);
for(int i=n--sum;i>=;i--)
divi(i,-);
for(int i=;i<=n;i++)
{
if(d[i]!=-)
{
for(int j=d[i]-;j>=;j--)
divi(j,-);
}
}
ans[]=ans[]=;
for(int i=;i<=n--sum;i++)
mult(ans,n-cnt);
for(int i=;i<=tot;i++)
while(bu[i])mult(ans,pri[i]),bu[i]--;
for(int i=ans[];i>=;i--)
printf("%d",ans[i]);
return ;
}

bzoj1211树的计数 x bzoj1005明明的烦恼 题解(Prufer序列)的更多相关文章

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

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

  2. [HNOI2008][bzoj 1005]明明的烦恼(prufer序列)

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

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

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

  4. HNOI2004 树的计数 和 HNOI2008 明明的烦恼

    树的计数 输入文件第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树的第i个结点的度数.其中1<=n<=150,输入数据保证满足条件的树不超过10^17个. 明 ...

  5. [HNOI2008]明明的烦恼(prufer序列,高精度,质因数分解)

      prufer序列 定义 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2. 描述 eg 将 ...

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

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

  7. [BZOJ1005][HNOI2008]明明的烦恼 数学+prufer序列+高精度

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int N; ...

  8. [HNOI2004][bzoj1211] 树的计数(prufer序列)

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3432  Solved: 1295[Submit][Stat ...

  9. BZOJ1005明明的烦恼 Prufer + 分解質因數 + 高精度

    @[高精度, Prufer, 質因數分解] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多 ...

随机推荐

  1. ldap yum安装-centos6

    yum安装openldap 系统环境信息 操作系统:CentOS release 6.7 基础的环境准备 iptables -F && /etc/init.d/iptables sav ...

  2. (转)使用OpenGL显示图像(二)定义Shapes

    定义形状 编写:jdneo - 原文:http://developer.android.com/training/graphics/opengl/shapes.html 在一个OpenGL ES Vi ...

  3. 86、使用Tensorflow实现,LSTM的时间序列预测,预测正弦函数

    ''' Created on 2017年5月21日 @author: weizhen ''' # 以下程序为预测离散化之后的sin函数 import numpy as np import tensor ...

  4. Java关于Math类的三个取整方法

    0x01 在java的Math类中有三个关于浮点数取整数的方法,分别是ceil (向上取整) floor(向下取整) round(四舍五入) 三个方法 0x02 ceil 向上取整,取整后总是比原来的 ...

  5. 74HC AHCT LS LV ABT区别

    1. 含义 2. 74AHC 74AHCT 74LV 74LS 2.1 解释 AHC与AHCT均是先进的高速的CMOS器件,但是供电电压范围不同,输入的逻辑电平也不同. LV是低压版,当自身供电电压为 ...

  6. Reactor 反应堆设计模式

    为了应对高并发的服务器端开发,微软在2009年提出了一种更优雅地实现异步编程的方式Reactive Programming即反应式编程.随后其他技术紧随其后,比如ES6通过引入类似的异步编程方式等. ...

  7. Django框架(十六)—— cookie和session组件

    目录 cookie和session组件 一.cookie 1.cookie的由来 2.什么是cookie 3.cookie的原理 4.cookie的覆盖 5.在浏览器中查看cookie 6.cooki ...

  8. PHP中使用raw格式发送POST请求

    如果请求的参数格式是原生(raw)的内容,应该如何为程序构造一个POST请求函数呢? function http_post($url, $data_string) { $ch = curl_init( ...

  9. CentOS 7.4安装telnet服务端

    CentOS 7.4安装telnet服务端 安装xinetd服务 # yum -y install xinetd 安装telnet-server # yum -y install telnet-ser ...

  10. Maven的pom.xml文件结构之基本配置parent和继承结构

    1.Maven项目的继承 Maven项目之间不仅存在多模块的聚合关系,而且Maven项目之间还可以存在相互继承的关系. Maven项目之间的继承关系通过<parent>表示,在子Maven ...