1211: [HNOI2004]树的计数

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 3432  Solved: 1295
[Submit][Status][Discuss]

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
 
 
 

先丟几个Prufer序列的性质:

1.与无根树一一对应。

2.度数为$d_i$的点会在Prufer序列中出现$d_i-1$次。

3.一个$n$个节点的完全图的生成树个数为$n^{n-2}$

  解释一下:prufer序列长为$n-2$,每个位置有$n$种可能性。

4.对于给定每个点度数的无根树,共有$\frac{(n-2)!}{\prod \limits _{i=1}^n {(d_i-1)!}}$种情况。

  其实就是$d_i-1$个$i$的可重全排列。

那么这道题就用上面这个结论切掉就好了。求组合数直接分解质因数,记得要特判$n==1$及不联通的情况。

#include<cstdio>
#include<iostream>
#include<cstring>
const int N=;
int d[N],n;
int vis[N],pri[N],res[N],tot,sum,ans[N*],bu[N];
void getprime()
{
for(int i=;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,res[i]=tot;
for(int j=;j<=tot;j++)
{
if(pri[j]*i>n)break;
vis[i*pri[j]]=;res[i*pri[j]]=j;
if(i%pri[j]==)break;
}
}
}
void divi(int x,int val)
{
while(x!=)bu[res[x]]+=val,x/=pri[res[x]];
}
void mult(int a[],int x)
{
int k=;
for(int i=;i<=a[];i++)
{
int tmp=a[i]*x+k;
a[i]=tmp%;
k=tmp/;
}
while(k)a[++a[]]=k%,k/=;
}
int main()
{
scanf("%d",&n);
if(n==)
{
int deg;
scanf("%d",&deg);
if(!deg)puts("");
else puts("");
return ;
}
getprime();
for(int i=;i<=n;i++)
{
scanf("%d",&d[i]);
if(!d[i])
{
puts("");
return ;
}
sum+=d[i]-;
}
if(sum!=n-)
{
puts("");
return ;
}
for(int i=n-;i>=;i--)
divi(i,);
for(int i=;i<=n;i++)
{
for(int j=d[i]-;j>=;j--)
divi(j,-);
}
ans[]=ans[]=;
for(int i=;i<=tot;i++)
while(bu[i]--)mult(ans,pri[i]);
for(int i=ans[];i;i--)
printf("%d",ans[i]);
return ;
}

1005: [HNOI2008]明明的烦恼

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7125  Solved: 2818
[Submit][Status][Discuss]

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

本题的问题在于有的点度数是不确定的。

所以我们先求出$sum=\sum d_i-1$,之后从总长度$n-2$中选出这些

对于剩下的不确定度数的部分,我们设已知度数点的个数为$cnt$

那么现在有$n-2-sum$个位置可以任意排列$n-cnt$个点

易得最终答案为

$C_{n-2}^{sum}*\frac{(n-2)!}{\prod \limits _{i=1}^{cnt} {(d_i-1)!}}*(n-cnt)^{n-2-sum}$

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=;
int d[N],n;
int vis[N],pri[N],res[N],tot,sum,cnt,ans[N*],bu[N];
void getprime()
{
for(int i=;i<=n;i++)
{
if(!vis[i])pri[++tot]=i,res[i]=tot;
for(int j=;j<=tot;j++)
{
if(pri[j]*i>n)break;
vis[i*pri[j]]=;res[i*pri[j]]=j;
if(i%pri[j]==)break;
}
}
}
void divi(int x,int val)
{
while(x!=)bu[res[x]]+=val,x/=pri[res[x]];
}
void mult(int a[],int x)
{
int k=;
for(int i=;i<=a[];i++)
{
int tmp=a[i]*x+k;
a[i]=tmp%;
k=tmp/;
}
while(k)a[++a[]]=k%,k/=;
} int main()
{
scanf("%d",&n);
getprime();
for(int i=;i<=n;i++)
{
scanf("%d",&d[i]);
if(d[i]!=-)sum+=d[i]-,cnt++;
}
for(int i=n-;i>=;i--)
divi(i,);
for(int i=n--sum;i>=;i--)
divi(i,-);
for(int i=;i<=n;i++)
{
if(d[i]!=-)
{
for(int j=d[i]-;j>=;j--)
divi(j,-);
}
}
ans[]=ans[]=;
for(int i=;i<=n--sum;i++)
mult(ans,n-cnt);
for(int i=;i<=tot;i++)
while(bu[i])mult(ans,pri[i]),bu[i]--;
for(int i=ans[];i>=;i--)
printf("%d",ans[i]);
return ;
}

bzoj1211树的计数 x bzoj1005明明的烦恼 题解(Prufer序列)的更多相关文章

  1. 【BZOJ1005】[HNOI2008]明明的烦恼(prufer序列)

    [BZOJ1005][HNOI2008]明明的烦恼(prufer序列) 题面 BZOJ 洛谷 题解 戳这里 #include<iostream> #include<cstdio> ...

  2. [HNOI2008][bzoj 1005]明明的烦恼(prufer序列)

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

  3. 2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?)

    2021.07.19 P2624 明明的烦恼(prufer序列,为什么杨辉三角我没搞出来?) [P2624 HNOI2008]明明的烦恼 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn ...

  4. HNOI2004 树的计数 和 HNOI2008 明明的烦恼

    树的计数 输入文件第一行是一个正整数n,表示树有n个结点.第二行有n个数,第i个数表示di,即树的第i个结点的度数.其中1<=n<=150,输入数据保证满足条件的树不超过10^17个. 明 ...

  5. [HNOI2008]明明的烦恼(prufer序列,高精度,质因数分解)

      prufer序列 定义 Prufer数列是无根树的一种数列.在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2. 描述 eg 将 ...

  6. 【洛谷2624_BZOJ1005】[HNOI2008] 明明的烦恼(Prufer序列_高精度_组合数学)

    题目: 洛谷2624 分析: 本文中所有的 "树" 都是带标号的. 介绍一种把树变成一个序列的工具:Prufer 序列. 对于一棵 \(n\) 个结点的树,每次选出一个叶子(度数为 ...

  7. [BZOJ1005][HNOI2008]明明的烦恼 数学+prufer序列+高精度

    #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int N; ...

  8. [HNOI2004][bzoj1211] 树的计数(prufer序列)

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3432  Solved: 1295[Submit][Stat ...

  9. BZOJ1005明明的烦恼 Prufer + 分解質因數 + 高精度

    @[高精度, Prufer, 質因數分解] Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在 任意两点间连线,可产生多 ...

随机推荐

  1. UNP学习 广播

    一.概述 虽然UDP支持各种形式的地址,但TCP只支持单播地址. 上图要点是: IPv4对多播的支持是可选的,而IPv6则时必须的. IPv6没有提供对广播的支持:当使用广播的IPv4应用程序一直到I ...

  2. 轻松解决U盘拷贝文件时提示文件过大问题

    现在的高科技时代生活中,u盘的使用已经是许多从事电脑it行业的人每天都必须要用到的用具.可以在一台电脑上使用u盘拷贝文件到另外一台电脑上进行使用,加上它的身材小巧,非常方便我们随身携带到任何地方进行使 ...

  3. <Jmeter入门不放弃>之<3.两种常见录制脚本的方法>

    关于录制,我想表达的是,并不要以为他很低端,解决需求才是王道,大家这里参考学习的时候,我就不在这里配截图了,因为需要你打开工具根据文档自己去找,才有印象,大家一定要启动JMeter!跟着理解操作 录制 ...

  4. django更换默认数据库sqlite3为pymsql后出现Keyerror:255的解决办法----升级PyMySQL

    一.更换数据库的办法: 1.安装PyMySQL 2.修改project目录同名文件下的settings.py:DATABASES = { 'default': { # 'ENGINE': 'djang ...

  5. python 比较俩个列表中的元素是否相同

    如果元素都是数字: # a = [121, 144, 19, 161, 19, 144, 19, 11]# b = [121, 14641, 20736, 361, 25921, 361, 20736 ...

  6. Android 测试点归纳总结

    前言 除了测试平台工具,业务测试的总结和思考同样重要,这里总结了一些Android测试知识点,可以辅助业务测试快速形成测试用例和检查点,当作抛砖引玉分享给大家.如有思考不全面的地方,欢迎大家指出来. ...

  7. mybatis的sqlprovider用法扩展自定义sql

    SqlProvider使用 public class MemberRewardSqlProvider { private static final Logger log = LoggerFactory ...

  8. PAT_A1089#Insert or Merge

    Source: PAT A1089 Insert or Merge (25 分) Description: According to Wikipedia: Insertion sort iterate ...

  9. CF_127E reader Display

    这道题其实找到规律之后其实不难,和破损的键盘一样,都有点递推转移的感觉 题意: 你可以进行这样一次操作:选一个点,然后把这个点横切竖切直到正对角线上面的点,全部翻转过来,问你要进行多少次操作才能把所有 ...

  10. Money

    /** * www.yiji.com Inc. * Copyright (c) 2012 All Rights Reserved. */package com.yjf.common.lang.util ...