http://www.lydsy.com/JudgeOnline/problem.php?id=1005

这里讲得挺清楚的:http://www.cnblogs.com/zhj5chengfeng/p/3278557.html

对于有n个节点的树:

prufer数列和一棵树一一对应。

prufer数列有n-2个元素

prufer数列的构造与解析:

构造:n-2步,每一步在树中查找度为1的标号最小的点,并将这个点所在的边的另一个点放到prufer数列中,两个点的度均-1。

解析:将所有点的度赋值为1,然后将prufer数列的每个元素加上出现次数。n-2步,当前是第i步,找度为1的标号最小点,与prufer的第i个元素连边,两个点的度均-1。最后还剩下两个度为1的点,连边。

于是我们只需要找n-2个元素的排列方案即可。

因为只有d[i]>1的点才会出现在prufer数列中,且次数为d[i]-1,所以我们设

$$sum=\sum_{i=1}^{cnt} (d[i]-1)$$

其中$cnt$表示所有度均为已知的个数。(这里注意,度为1的点也必须算在内,因为他们必然不在prufer数列上,因此方案一一对应。)

然后我们有n-2个格子,那么可以根据多重排列知识,如果有$sum$个放到n-2个格子上,有排列数

$$\frac{sum!}{\prod_{i=1}^{cnt} (d[i]-1)!}$$

那么我们从n-2个格子选出sum个的方案有

$$\dbinom{n-2}{sum}$$

所以从n-2个取sum个的总排列有

$$\dbinom{n-2}{sum} \times \frac{sum!}{\prod_{i=1}^{cnt} (d[i]-1)!}$$

那么考虑还剩余的$n-cnt$个,因为此时还有$n-2-sum$个格子,那么考虑每一个点放在哪个格子的方案就是

$$(n-cnt)^{n-2-sum}$$

然后乘法将两个式子乘起来就是有解的方案了,可以化简为:

$$\frac{(n-2)!}{(n-2-sum)! \times \prod_{i=1}^{cnt} (d[i]-1)!} \times (n-cnt)^{n-2-sum}$$

对于无解的情况,因为只有n-2个格子,因此当sum>n-2,无解。

此外本题还要特判n=1的情况

如果暴力去解决,那么很麻烦。。根据组合知识,我们知道组合一定是能被整除的,那么我们将分子分母分解成质因数的乘积,然后指数加减最后乘起来就行了。。orz

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next) const int N=1005;
int prime[N], cnt, notprime[N], p[N][N], ans[N];
void add(int *arr, int x, int s) {
for1(i, 1, cnt) while(x%prime[i]==0) arr[i]+=s, x/=prime[i];
}
void add(int *h, int s) {
for1(i, 1, cnt) if(h[i]) ans[i]+=s*h[i];
}
void init() {
for1(i, 2, 1000) {
if(!notprime[i]) prime[++cnt]=i;
for(int j=1; j<=cnt && prime[j]*i<=1000; ++j) {
notprime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
p[2][1]=1;
for1(i, 3, 1000) {
memcpy(p[i], p[i-1], sizeof(p[i]));
add(p[i], i, 1);
}
}
int n, d[N], sum, w, ans2[10005];
void mul(int *a, int c) {
int i=1;
for(i=1; i<=a[0]; ++i) a[i]*=c;
for(i=1; i<=a[0]; ++i) {
a[i+1]+=a[i]/10;
a[i]%=10;
}
while(a[i]>=10) { a[i+1]+=a[i]/10; a[i]%=10; ++i; }
while(i>1 && a[i]==0) --i;
a[0]=i;
}
void P(int *a) {
for3(i, a[0], 1) printf("%d", a[i]);
}
int main() {
read(n);
if(n==1) { int x=getint(); if(x==0) puts("1"); else puts("0"); return 0; }
for1(i, 1, n) { read(d[i]); if(d[i]!=-1) sum+=d[i]-1, ++w; }
if(sum>n-2) { puts("0"); return 0; }
init();
for1(i, 1, n-2-sum) add(ans, n-w, 1);
add(p[n-2], 1);
add(p[n-2-sum], -1);
for1(i, 1, n) if(d[i]>1) add(p[d[i]-1], -1);
ans2[0]=ans2[1]=1;
for1(i, 1, cnt) while(ans[i]) mul(ans2, prime[i]), --ans[i];
P(ans2);
return 0;
}

  


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

Source

【BZOJ】1005: [HNOI2008]明明的烦恼(prufer编码+特殊的技巧)的更多相关文章

  1. BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)

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

  2. bzoj 1005 [HNOI2008] 明明的烦恼 (prufer编码)

    [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5907  Solved: 2305[Submit][Status][Di ...

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

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2248  Solved: 898[Submit][Statu ...

  4. BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)

    题目链接 若点数确定那么ans = (n-2)!/[(d1-1)!(d2-1)!...(dn-1)!] 现在把那些不确定的点一起考虑(假设有m个),它们在Prufer序列中总出现数就是left=n-2 ...

  5. BZOJ 1005 [HNOI2008]明明的烦恼 ★(Prufer数列)

    题意 N个点,有些点有度数限制,问这些点可以构成几棵不同的树. 思路 [Prufer数列] Prufer数列是无根树的一种数列.在组合数学中,Prufer数列是由一个对于顶点标过号的树转化来的数列,点 ...

  6. BZOJ 1005 [HNOI2008] 明明的烦恼(组合数学 Purfer Sequence)

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

  7. BZOJ 1005: [HNOI2008]明明的烦恼( 组合数学 + 高精度 )

    首先要知道一种prufer数列的东西...一个prufer数列和一颗树对应..然后树上一个点的度数-1是这个点在prufer数列中出现次数..这样就转成一个排列组合的问题了.算个可重集的排列数和组合数 ...

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

    1005: [HNOI2008]明明的烦恼 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/ ...

  9. BZOJ 1005 [HNOI2008]明明的烦恼 purfer序列,排列组合

    1005: [HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少 ...

  10. BZOJ 1005: [HNOI2008]明明的烦恼(prufer数列)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1005 题意: Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标 ...

随机推荐

  1. BMFONT 字体制作

    原地址:http://blog.csdn.net/luyuncsd123/article/details/18351057 网上搜BMFont做字体,很多都是从一个字体文件读取,然后选择需要的字,然后 ...

  2. 转:不在同一个服务器上的数据库之间的数据操作(oracle/sql server的对比)

    如何操做不在同一个数据库中的数据操作: 一.对于SQL server来讲:  1.采用创建链接服务器的方式:    (1).创建链接服务器       exec sp_addlinkedserver  ...

  3. js 字符串indexof与search方法的区别

    1.indexof方法 indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. 语法: 注意:有可选的参数(即设置开始的检索位置). 2.search方法 search() 方法用 ...

  4. ‘close’ was not declared in this scope

    ‘close’ was not declared in this scope ‘read’ was not declared in this scope ‘sysconf’ was not decla ...

  5. DBMS_METADATA中使用SESSION_TRANSFORM过滤不想获取的DDL

    我们一般使用dbms_metadata.get_ddl获取对象的ddl的时候,有时会获取一些其它额外的信息,比如当你想获取表的创建语句的时候,你会得到表的约束信息,这个信息可能是你不想要的,那么就能够 ...

  6. 〖Android〗巧用/system/etc/mkshrc文件,把busybox常用命令映射(链接)出来;

    在/system/etc/mkshrc文中尾部添加以下代码即可: # for busybox for n in $(busybox --list) do eval alias $n=\'busybox ...

  7. Apache Ant和Apache Maven的区别

    Apache Ant和Apache Maven的区别 分类: ANT Maven 2013-12-10 18:47 1477人阅读 评论(26) 收藏 举报 ———摘自<maven权威指南> ...

  8. 用Html写一个简单的登陆界面

    <!DOCTYPE html> <html> <title>登陆页面</title> <head> <meta charset=&qu ...

  9. 迅为4412开发板Linux驱动教程——总线_设备_驱动注冊流程具体解释

    视频下载地址: 驱动注冊:http://pan.baidu.com/s/1i34HcDB 设备注冊:http://pan.baidu.com/s/1kTlGkcR 总线_设备_驱动注冊流程具体解释 • ...

  10. Dbvisual连接远程数据库报错Error Code: 17401

    Long Message:违反协议 Details:   Type: java.sql.SQLException   Error Code: 17401   SQL State: null 现象: 本 ...