[HNOI 2004]树的计数
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
2 1 2 1
Sample Output
题解
$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]树的计数的更多相关文章
- 树的计数 + prufer序列与Cayley公式 学习笔记
首先是 Martrix67 的博文:http://www.matrix67.com/blog/archives/682 然后是morejarphone同学的博文:http://blog.csdn.ne ...
- 【BZOJ】【1211】【HNOI2004】树的计数
Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明 ...
- BZOJ1211: [HNOI2004]树的计数
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1245 Solved: 383[Submit][Statu ...
- BZOJ 1211: [HNOI2004]树的计数( 组合数学 )
知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...
- 「NOI2013」树的计数 解题报告
「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...
- loj#2665. 「NOI2013」树的计数
目录 题目链接 题解 代码 题目链接 loj#2665. 「NOI2013」树的计数 题解 求树高的期望 对bfs序分层 考虑同时符合dfs和bfs序的树满足什么条件 第一个点要强制分层 对于bfs序 ...
- 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2468 Solved: 868 Description 一 ...
- bzoj1211: [HNOI2004]树的计数 prufer编码
题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...
- UOJ #122 【NOI2013】 树的计数
题目链接:树的计数 这道题好神啊……正好有人讲了这道题,那么我就写掉吧…… 首先,为了方便考虑,我们可以把节点重标号,使得\(bfs\)序变成\(1,2,3,\dots,n\),那么显然树的深度就是\ ...
随机推荐
- C语言第五次博客作业
一.PTA实验作业 题目1:6-6 使用函数输出水仙花数 1. 本题PTA提交列表 2. 设计思路 (1) 首先先定义narcissistic函数. (2)定义四个整形变量n,a,d,cnt,sum, ...
- 张金禹 C语言--第0次作业
1:在填报专业的时候,我也犹豫了很久,但最后还是选择了计算机专业.因为在上大学之前我就对编程.设计等有浓厚的兴趣,但繁重的高中学习任务使我没有过多的去关注,所以我选择了计算机专业去培养我在这方面的兴趣 ...
- 201621123044《JAVA程序设计》第一周学习总结
1. 本周学习总结 1.了解了JAVA的诞生以及发展历史简介.JAVA语言的特点,以及JAVA的电脑安装以及环境配置. 2.JAVA不仅可以用eclipse进行编写,也可以在记事本和notepad++ ...
- vmware ubuntu蓝屏
ctrl+alt+f4 sudo apt-get update sudo apt-get upgrade sudo apt-get install xserver-xorg-lts-utopic su ...
- velocity学习总结
什么是velocity velocity是一个基于Java的模板引擎,它可以实现彻底的前后端,前端不允许像jsp那样出现Java代码,而是利用context容器传递变量,在java代码里面我们可以往容 ...
- PHP环境手动搭建wamp-----Apache+MySQL+PHP
首先下载分别下载Apache+MySQL+PHP. 然后分别解压到文件夹中. 1.安装Apache 1)检查80端口是否占用 说明:apache软件占用80软件,在计算机中一个端口只能被一个软件占用 ...
- 将Python程序打包为exe方法
将Python程序打包为exe文件,需要使用到的工具是pyinstaller pyinstaller是一个多平台的Python程序打包为exe的免费工具 安装pyinstaller: 1,在Windo ...
- javascript递归函数
递归函数:是指函数直接或间接调用函数本身,则称该函数为递归函数. 这句话理解起来并不难,从概念上出发,给出以下的例子: function foo(){ console.log("函数 foo ...
- Class-Based-View(CBV)
我们都知道,Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承.封装.多态).所以Django在后来加入了Class-Based-View.可以让我们用类写V ...
- WPF treeview扩展
记录一下工作中遇到的问题,以便以后忘记了可以来看. 在工作中遇到一个问题,就是要实现类型如下的界面,没有使用Telerik和Dev库.本来最开始是想使用Datagrid,但不知道怎么实现treevie ...