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

题解

$Prüfer$编码&$Cayley$公式。

预备知识:->戳我<-

这里谈下自己的理解:

(此段与题目无关,可选择跳过)首先对于$Cayley$公式,其实讲的就是“$n$阶完全图生成数个数为$n^{n-2}$”,换言之就是“$n$个带编号顶点的无根生成树共$n^{n-2}$个”。

证明:这里引用$Prüfer$编码,不了解的话可以戳上文链接。其实就是对于任何一棵无根生成树,都有一个长度为$n-2$的序列。这个序列是这样定义的:每次在叶节点中找到一个编号最小的节点,将其删去,记录下相邻节点。因为是无根,若顶点只有$2$个,显然只有一棵树,长度就是$n-2$。

而对于任何一个$Prüfer$编码都能够还原成一棵无根树。

我们回到这道题,我们拥有这样一个结论:“任何一个$Prüfer$编码都能够还原成一棵无根树”。

那么我们就可以用$Prüfer$编码来解决问题。

我们发现第$i$个点会在$Prüfer$编码中出现$d[i]-1$次:因为自己“被删”需要$1$个度,他的其他相邻节点“被删”要$d[i]-1$个度。

那么等于说$i$这个数会在编码中出现$d[i]-1$次。

因为数列长度为$n-2$,我们看有序排列:总共有$(n-2)!$个

考虑去重:因为此时$Prüfer$编码中的数字$i$恰好出现$d[i]-1$次我们只需要对于每个$i$都除以$(d[i]-1)!$就可以了。

所以答案就是

注意要特殊讨论构成不了树的情况。

 //It is made by Awson on 2017.10.6
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define sqr(x) ((x)*(x))
using namespace std;
void read(int &x) {
char ch; bool flag = ;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || ); ch = getchar());
for (x = ; isdigit(ch); x = (x<<)+(x<<)+ch-, ch = getchar());
x *= -*flag;
} int n, a[];
int cnt[];
int pre[]; void prepare() {
bool isprime[];
int q[], top = ;
memset(isprime, , sizeof (isprime));
isprime[] = ;
for (int i = ; i <= n; i++) {
if (isprime[i]) q[++top] = i;
for (int j = ; j <= top && i*q[j] <= n; j++) {
pre[i*q[j]] = q[j];
isprime[i*q[j]] = ;
if (i%q[j] == ) break;
}
}
}
void noanswer() {
printf("0\n");
exit();
}
void work() {
read(n);
prepare();
int sum = ;
for (int i = ; i <= n; i++) {
read(a[i]);
if (!a[i] && n != ) noanswer();
a[i]--; sum += a[i];
}
if (sum != n-) noanswer();
for (int i = ; i <= n-; i++) {
int j = i;
while (pre[j]) {
cnt[pre[j]]++;
j /= pre[j];
}
cnt[j]++;
}
for (int i = ; i <= n; i++)
for (int j = ; j <= a[i]; j++) {
int k = j;
while (pre[k]) {
cnt[pre[k]]--;
k /= pre[k];
}
cnt[k]--;
}
LL ans = ;
for (int i = ; i <= n; i++)
for (int j = ; j <= cnt[i]; j++)
ans *= i;
printf("%lld\n", ans);
}
int main() {
work();
return ;
}

[HNOI 2004]树的计数的更多相关文章

  1. 树的计数 + prufer序列与Cayley公式 学习笔记

    首先是 Martrix67 的博文:http://www.matrix67.com/blog/archives/682 然后是morejarphone同学的博文:http://blog.csdn.ne ...

  2. 【BZOJ】【1211】【HNOI2004】树的计数

    Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明 ...

  3. BZOJ1211: [HNOI2004]树的计数

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1245  Solved: 383[Submit][Statu ...

  4. BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

    知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...

  5. 「NOI2013」树的计数 解题报告

    「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...

  6. loj#2665. 「NOI2013」树的计数

    目录 题目链接 题解 代码 题目链接 loj#2665. 「NOI2013」树的计数 题解 求树高的期望 对bfs序分层 考虑同时符合dfs和bfs序的树满足什么条件 第一个点要强制分层 对于bfs序 ...

  7. 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2468  Solved: 868 Description 一 ...

  8. bzoj1211: [HNOI2004]树的计数 prufer编码

    题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...

  9. UOJ #122 【NOI2013】 树的计数

    题目链接:树的计数 这道题好神啊……正好有人讲了这道题,那么我就写掉吧…… 首先,为了方便考虑,我们可以把节点重标号,使得\(bfs\)序变成\(1,2,3,\dots,n\),那么显然树的深度就是\ ...

随机推荐

  1. C语言第五次博客作业

    一.PTA实验作业 题目1:6-6 使用函数输出水仙花数 1. 本题PTA提交列表 2. 设计思路 (1) 首先先定义narcissistic函数. (2)定义四个整形变量n,a,d,cnt,sum, ...

  2. 张金禹 C语言--第0次作业

    1:在填报专业的时候,我也犹豫了很久,但最后还是选择了计算机专业.因为在上大学之前我就对编程.设计等有浓厚的兴趣,但繁重的高中学习任务使我没有过多的去关注,所以我选择了计算机专业去培养我在这方面的兴趣 ...

  3. 201621123044《JAVA程序设计》第一周学习总结

    1. 本周学习总结 1.了解了JAVA的诞生以及发展历史简介.JAVA语言的特点,以及JAVA的电脑安装以及环境配置. 2.JAVA不仅可以用eclipse进行编写,也可以在记事本和notepad++ ...

  4. vmware ubuntu蓝屏

    ctrl+alt+f4 sudo apt-get update sudo apt-get upgrade sudo apt-get install xserver-xorg-lts-utopic su ...

  5. velocity学习总结

    什么是velocity velocity是一个基于Java的模板引擎,它可以实现彻底的前后端,前端不允许像jsp那样出现Java代码,而是利用context容器传递变量,在java代码里面我们可以往容 ...

  6. PHP环境手动搭建wamp-----Apache+MySQL+PHP

    首先下载分别下载Apache+MySQL+PHP. 然后分别解压到文件夹中. 1.安装Apache 1)检查80端口是否占用 说明:apache软件占用80软件,在计算机中一个端口只能被一个软件占用 ...

  7. 将Python程序打包为exe方法

    将Python程序打包为exe文件,需要使用到的工具是pyinstaller pyinstaller是一个多平台的Python程序打包为exe的免费工具 安装pyinstaller: 1,在Windo ...

  8. javascript递归函数

    递归函数:是指函数直接或间接调用函数本身,则称该函数为递归函数. 这句话理解起来并不难,从概念上出发,给出以下的例子: function foo(){ console.log("函数 foo ...

  9. Class-Based-View(CBV)

    我们都知道,Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承.封装.多态).所以Django在后来加入了Class-Based-View.可以让我们用类写V ...

  10. WPF treeview扩展

    记录一下工作中遇到的问题,以便以后忘记了可以来看. 在工作中遇到一个问题,就是要实现类型如下的界面,没有使用Telerik和Dev库.本来最开始是想使用Datagrid,但不知道怎么实现treevie ...