[HNOI2008]明明的烦恼
2017-12-24 18:12
169 查看
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0Sample Input
31
-1
-1
Sample Output
2HINT
两棵树分别为1-2-3;1-3-2[b]该题运用到了树的prufer编码的性质:[/b]
[b] (1)树的prufer编码的实现[/b]
[b] 不断 删除树中度数为1的最小序号的点,并输出与其相连的节点的序号 直至树中只有两个节点[/b]
[b] (2)通过观察我们可以发现[/b]
[b] 任意一棵n节点的树都可唯一的用长度为n-2的prufer编码表示[/b]
[b] 度数为m的节点的序号在prufer编码中出现的次数为m-1[/b]
[b] (3)怎样将prufer编码还原为一棵树??[/b]
[b] 从prufer编码的最前端开始扫描节点,设该节点序号为 u ,寻找不在prufer编码的最小序号且没有被标记的节点 v ,连接 u,v,并标记v,将u从prufer编码中删除。扫描下一节点。[/b]
[b]该题需要将树转化为prufer编码[/b]
[b]因为一个点度为di,那么在prufer序列中出现di-1次[/b]
[b]所以对于已知的度,sum=∑di-1(已知),cnt为有多少已知点[/b]
[b]那么从序列中选出sum为方案C(sum,n-2)[/b]
[b]对于已知di,产生的方案数为${{(n-2)!} \over {\prod (d_i - 1)}}$[/b]
[b]对于无限制的点,可以这样考虑,剩下的n-2-sum为每一位选择都有n-cnt种[/b]
[b]所以方案为(n-cnt)n-2-sum[/b]
[b]把三者乘起来[/b]
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct Big_Num { int a[5005],len; Big_Num() {} Big_Num &operator *=(const int &b) {int i; for (i=1;i<=len;i++) a[i]*=b; for (i=1;i<=len;i++) a[i+1]+=a[i]/10,a[i]%=10; int loc=len+1; while (a[loc]) { a[loc+1]+=a[loc]/10; a[loc]%=10; loc++; } len=loc-1; } void print() {int i; for (i=len;i>=1;i--) printf("%d",a[i]); cout<<endl; } }ans; int d[1001],du[2001],pri[2001],pre[2001],tot,n,cnt,sum,flag; bool vis[2001]; int main() {int i,j; freopen("tree1.in","r",stdin); freopen("1005.out","w",stdout); cin>>n; flag=0; for (i=1;i<=n;i++) { scanf("%d",&d[i]); if (d[i]!=-1) cnt++,sum+=d[i]-1; if (d[i]==0||d[i]==n) flag=1; } if (n==1) { cout<<1; return 0; } if (n==2) { if ((d[1]==0||d[1]>1)||(d[2]==0||d[2]>1)) cout<<0; else cout<<1; return 0; } if (sum>n-2) { cout<<0; return 0; } if (flag) { cout<<0; return 0; } for (i=2;i<=n-2;i++) du[i]++; for (i=2;i<=n-2-sum;i++) du[i]--; for (i=1;i<=n;i++) if (d[i]!=-1) { for (j=2;j<=d[i]-1;j++) du[j]--; } for (i=1;i<=n-2-sum;i++) du[n-cnt]++; for (i=2;i<=2000;i++) { if (vis[i]==0) { pri[++tot]=i; pre[i]=i; } for (j=1;j<=tot;j++) { if (pri[j]*i>2000) break; vis[i*pri[j]]=1; pre[i*pri[j]]=pri[j]; if (i%pri[j]==0) break; } } for (i=2000;i>=2;i--) if (pre[i]!=i) { du[pre[i]]+=du[i]; du[i/pre[i]]+=du[i]; du[i]=0; } ans.a[1]=1;ans.len=1; for (i=2;i<=2000;i++) if (du[i]>0) { for (j=1;j<=du[i];j++) ans*=i; } ans.print(); }
相关文章推荐
- 【BZOJ1005】【HNOI2008】明明的烦恼
- [prufer序列]BZOJ1005: [HNOI2008]明明的烦恼
- [HNOI2008]明明的烦恼 (Prüfer编码+质因数分解计算两个阶乘的商)
- 【Prufer数列/组合数学】[HNOI2008][HYSBZ/BZOJ1005]明明的烦恼
- 【Prufer编码+组合】BZOJ1005(HNOI2008)[明明的烦恼]题解
- [BZOJ1005](HNOI 2008)明明的烦恼
- 【Purfer】【bzoj 1005】: [HNOI2008]明明的烦恼
- [HNOI2008]明明的烦恼
- [BZOJ]1005 明明的烦恼(HNOI2008)
- BZOJ 1005([HNOI2008]明明的烦恼-Prufer数列-树与数组的一一对应)
- 【BZOJ 1005】【HNOI 2008】明明的烦恼
- bzoj 1005: [HNOI2008]明明的烦恼
- bzoj [1005] [HNOI2008]明明的烦恼
- [bzoj1005][HNOI2008]明明的烦恼-Prufer编码+高精度
- 【HNOI2008】bzoj1005 明明的烦恼
- [HNOI2008]明明的烦恼 树的 prufer 编码
- bzoj 1005: [HNOI2008]明明的烦恼(prufer数列)
- BZOJ 1005 [HNOI2008]明明的烦恼
- BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数
- BZOJ1005: [HNOI2008]明明的烦恼