题目描述

给出标号为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!)}$ 。

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

注意特判无解的情况。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 100000000
using namespace std;
typedef long long ll;
struct data
{
int len;
ll v[400];
ll &operator[](int a) {return v[a];}
data operator+(data &a)
{
data ans;
memset(ans.v , 0 , sizeof(ans.v));
int i;
for(i = 0 ; i < len || i < a.len || ans[i] ; i ++ )
ans[i] += v[i] + a[i] , ans[i + 1] = ans[i] / mod , ans[i] %= mod;
ans.len = i;
return ans;
}
data operator*(int a)
{
data ans;
memset(ans.v , 0 , sizeof(ans.v));
int i;
for(i = 0 ; i < len || ans[i] ; i ++ )
ans[i] += v[i] * a , ans[i + 1] = ans[i] / mod , ans[i] %= mod;
ans.len = i;
return ans;
}
void write()
{
int i;
printf("%lld" , v[len - 1]);
for(i = len - 2 ; ~i ; i -- ) printf("%08lld" , v[i]);
puts("");
}
}ans;
int a[1010] , cnt[1010] , prime[1010] , tot , np[1010];
void init()
{
int i , j;
for(i = 2 ; i <= 1000 ; i ++ )
{
if(!np[i]) prime[++tot] = i;
for(j = 1 ; j <= tot && i * prime[j] <= 1000 ; j ++ )
{
np[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}
void solve(int x , int a)
{
int i , j;
for(i = 1 ; i <= tot ; i ++ )
for(j = x / prime[i] ; j ; j /= prime[i])
cnt[i] += a * j;
}
int main()
{
init();
int n , i , c1 = 0 , c2 = 0;
scanf("%d" , &n);
for(i = 1 ; i <= n ; i ++ )
{
scanf("%d" , &a[i]);
if(a[i] > 0) c1 += a[i] - 1;
else if(a[i] == -1) c2 ++ ;
else
{
puts("0");
return 0;
}
}
if(c1 > n - 2)
{
puts("0");
return 0;
}
solve(n - 2 , 1) , solve(n - 2 - c1 , -1);
for(i = 1 ; i <= n ; i ++ )
if(a[i] > 0)
solve(a[i] - 1 , -1);
ans[0] = ans.len = 1;
for(i = 1 ; i <= tot ; i ++ )
while(cnt[i] -- )
ans = ans * prime[i];
for(i = 1 ; i <= n - 2 - c1 ; i ++ ) ans = ans * c2;
ans.write();
return 0;
}

【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. PANIC: HOME is defined but could not find Nexus_4_API_22.ini file in $HOME/.android/avd (Note: avd is searched in the order of $ANDROID_AVD_HOME,$ANDROID_SDK_HOME/.android/avd and $HOME/.android/avd)

    sudo cp /root/.android/avd/*.ini  $Home/.android/avd/ sudo cp -r  /root/.android/avd/*.avd  $Home/.a ...

  2. POI导出excel文件样式

    需求: 公司业务和银行挂钩,各种形式的数据之间交互性比较强,这就涉及到了存储形式之间的转换 比如数据库数据与excel文件之间的转换 解决: 我目前使用过的是POI转换数据库和文件之间的数据,下边上代 ...

  3. 【转载】混编ObjectiveC++

    原文:混编ObjectiveC++ 最近有点炒冷饭的嫌疑,不过确实以前没有Git Or Blog的习惯,所以很多工作上的技术分享就存留在了电脑的文档里,现在还是想重新整理一下,再分享出来. 混编C++ ...

  4. 初识JMM

    目录 what is JMM? JMM变量存储结构 JMM三大特性 原子性 可见性 有序性 java 堆栈 静态存储 栈式存储 堆式存储 JVM是啥 参考<Inside JVM> what ...

  5. 使用IntelRealScene设备结合Cocos引擎实现体感游戏开发

    英特尔开发人员专区原文地址 Cocos游戏开发引擎对于广大开发者来说都比较熟悉,Intel RealScene是什么呢,简单理解是一种特殊的摄像头,可以捕捉用户的手势,面部表情等,进而实现AR,VR的 ...

  6. HBASE理论篇

    1.Hbase是什么 HBase是一种构建在HDFS之上的分布式.面向列的存储系统.在需要实时读写.随机访问超大规模数据集时,可以使用HBase. 尽管已经有许多数据存储和访问的策略和实现方法,但事实 ...

  7. RedHat yum源配置

    RedHat yum源配置 原本以为Redhat7 和Centos7是完全一样的,可是安装完Redhat7以后,使用yum安装软件,提示红帽操作系统未注册.在网上搜索教程,最后成功解决,解决方式是将y ...

  8. 《Cocos2d-x游戏开发实战精解》学习笔记4--实战一个简单的钢琴

    上一节学习了使用Cocos2d-x播放音乐的方法,但是那种方法一般只适合于播放较大的音乐,而一般比较短小的音乐(如游戏中的打斗.按键音效等)则要通过playEffect来播放.本节使用该方法以及之前学 ...

  9. ERROR [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序

    在用c#生成应用程序的时候,读写dbf时,open方法出错 ERROR [IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序 以前这个程序是用着好 ...

  10. redis利用key计时与计数

    计时 Setex 命令为指定的 key 设置值及其过期时间.如果 key 已经存在, SETEX 命令将会替换旧的值 基本命令: redis 127.0.0.1:6379> SETEX KEY_ ...