[BZOJ1005](HNOI 2008)明明的烦恼

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

分析

好久没有更新题解了。。。

很容易看出这是一道组合计数题。然而……如果没有图论基础是很难想出怎样构造的。。。不过我在今年四月份刚“入门”OI的时候有幸看到了省队RealCS的题解,提前接触到了带标号无根树计数的“prufer数列“>_<所以这次很快就写出了正解~(prufer数列详见Matrix67 的blog:http://www.matrix67.com/blog/archives/682)

首先,由prufer数列的性质我们知道:对于一棵给定的无根树,任意一个节点在这棵树的prufer数列中出现次数等于这个节点的度数 - 1。那么根据题目中的条件,我们就可以得到一个可重集排列问题:给定每个数字出现次数,求满足条件的排列个数。

1 /**************************************************************
  2     Problem: 1005
  3     User: AsmDef
  4     Language: C++
  5     Result: Accepted
  6     Time:20 ms
  7     Memory:820 kb
  8 ****************************************************************/
  9  
 10 #include <cctype>
 11 #include <cstdio>
 12 #include <cmath>
 13 #include <cstdlib>
 14 inline void getd(int &x){
 15     char c = getchar();
 16     bool minus = 0;
 17     while(!isdigit(c) && c != ‘-‘)c = getchar();
 18     if(c == ‘-‘)minus = 1, c = getchar();
 19     x = c - ‘0‘;
 20     while(isdigit(c = getchar()))x = x * 10 + c - ‘0‘;
 21     if(minus)x = -x;
 22 }
 23 /*======================================================*/
 24 const int maxn = 1010;
 25 struct BigN{
 26     #define base 1000000
 27     #define maxl 1000
 28     int A[maxl], len;
 29     BigN(){len = 1, A[0] = 0;}
 30     BigN &operator *= (int x){
 31         int i, mor = 0;
 32         for(i = 0;i < len || mor;++i){
 33             if(i < len)mor += A[i] * x;
 34             A[i] = mor % base;
 35             mor /= base;
 36         }
 37         if(i > len)len = i;
 38         return *this;
 39     }
 40 }ans;
 41 int N, S = 0, A[maxn], Acnt = 0, Bcnt = 0, prime[maxn], pcnt = 0;
 42 inline void euler(){
 43     int i, j;
 44     bool not_p[maxn] = {0};
 45     for(i = 2;i <= N;++i){
 46         if(!not_p[i])prime[pcnt++] = i;
 47         for(j = 0;j < pcnt;++j){
 48             if(prime[j] * i > N)break;
 49             not_p[prime[j]*i] = 1;
 50             if(i % prime[j] == 0)break;
 51         }
 52     }
 53 }
 54 inline void init(){
 55     getd(N);
 56     if(N == 0){putchar(‘0‘);exit(0);}
 57     int i, d;
 58     if(N == 1){
 59         getd(d);
 60         if(d == -1 || !d)putchar(‘1‘);
 61         else putchar(‘0‘);
 62         exit(0);
 63     }
 64     for(i = 1;i <= N;++i){
 65         getd(d);
 66         if(d == 0){putchar(‘0‘);exit(0);}
 67         if(d == -1) ++Bcnt;
 68         else {
 69             A[Acnt++] = d - 1;
 70             S += d - 1;
 71         }
 72     }
 73     if((S > N-2) || (S < N-2 && !Bcnt)){
 74         putchar(‘0‘);
 75         exit(0);
 76     }
 77     A[Acnt++] = N - 2 - S;
 78     S = N - 2;
 79     euler();
 80 }
 81 int powcnt[maxn] = {0};
 82 inline void res(int n){
 83     int i, j;
 84     for(i = 0;i < pcnt;++i){
 85         j = prime[i];
 86         while(j <= n){
 87             powcnt[i] -= n / j;
 88             if(powcnt[i] < 0){printf("0");exit(0);}
 89             j *= prime[i];
 90         }
 91     }
 92 }
 93 inline void work(){
 94     int i, j = Acnt - 1, p;
 95     ans.A[0] = 1;
 96     for(i = 1;i <= A[j];++i)
 97         ans *= Bcnt;
 98     for(i = 0;i < pcnt;++i){
 99         p = prime[i];
100         while(p <= S){
101             powcnt[i] += S / p;
102             p *= prime[i];
103         }
104     }
105     for(i = 0;i < Acnt;++i)
106         res(A[i]);
107     for(i = 0;i < pcnt;++i){
108         for(j = 1;j <= powcnt[i];++j)
109             ans *= prime[i];
110     }
111     i = ans.len - 1;
112     printf("%d", ans.A[i]);
113     while(i--)
114         printf("%06d", ans.A[i]);
115 }
116 int main(){
117     init();
118     work();
119     return 0;
120 }

Prufer数列+可重集排列+阶乘质因数分解

时间: 2024-08-14 04:49:11

[BZOJ1005](HNOI 2008)明明的烦恼的相关文章

【bzoj1005】[HNOI2008]明明的烦恼 Prufer序列+高精度

题目描述 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? 输入 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1 输出 一个整数,表示不同的满足要求的树的个数,无解输出0 样例输入 3 1 -1 -1 样例输出 2 题解 Prufer序列+高精度 Prufer序列:由一棵 $n$ 个点的树唯一产生的一个 $n-2$ 个数的序列. 生成方法:找到这棵树编号最小的叶子节点,将其

【BZOJ1005/1211】[HNOI2008]明明的烦恼/[HNOI2004]树的计数 Prufer序列+高精度

[BZOJ1005][HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1 Output 一个整数,表示不同的满足要求的树的个数,无解输出0 Sample Input 3 1 -1 -1 Sample Outp

【组合数学】【高精度】【prufer数列】【HNOI 2008】【bzoj 1005】明明的烦恼

1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3217 Solved: 1290 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣-- 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1 Output 一个

[HNOI2008]明明的烦恼

1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5090  Solved: 1986[Submit][Status][Discuss] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的

BZOJ 1005 明明的烦恼(Prufer数列)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1005 题意:给出一棵树的某些节点的度数d,有些未给.问满足这个条件的树有多少种? 思路:(1)Prufer 数列是无根树的一种数列.由一棵树可以构造出一个Prufer数列,Prufer数列可转化为原来的树.由树生成Prufer的一种简单方法是每次找出标 号最小的叶子节点将其父节点添加到Prufer数列并将该叶子节点删除.直到最后只剩下两个节点时结束.比如下面的这个树按照我们刚才的方法生

BZOJ_1005_ [HNOI2008]_明明的烦恼_(组合数学+purfer_sequence+高精度+分解因数)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1005 一棵树有n个点,给出没给节点的度,如果没有限制则为-1,求共有多少种可能的树. 分析 蒟蒻我肯定是不会做的,所以先来抄一段题解... 这题需要了解一种数列: Purfer Sequence 我们知道,一棵树可以用括号序列来表示,但是,一棵顶点标号(1~n)的树,还可以用一个叫做 Purfer Sequence 的数列表示 一个含有 n 个节点的 Purfer Sequence 有 n-

BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数

1005: [HNOI2008]明明的烦恼 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1005 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行

bzoj 1005: [HNOI2008]明明的烦恼 prufer编号&amp;&amp;生成树计数

1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Status] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣...... 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树? Input 第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度

BZOJ 1010 玩具装箱toy(四边形不等式优化DP)(HNOI 2008)

Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<