【BZOJ1211】树的计数(HNOI2004)-Prufer序列+组合计数
测试地址:树的计数
做法:本题需要用到Prufer序列+组合计数。
什么是Prufer序列呢?是这样的,对于一棵树,每次将其编号最小的节点删去,并在序列中加入这个点所连接的点的编号,这样直到最后只剩下
举个例子:求
那么回到这一题,我们可以把求合法的树的数量这个问题,转化成求合法的Prufer序列数量。这里有一个性质,假如一棵树中点
最后还有一个小问题:判定无解。无解肯定只有两种情况:1.
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
int n,d[310],tot=0,sum[310][310]={0},ans[310];
ll p[310];
bool prime[310]={0};
void calc_prime(int limit)
{
for(ll i=2;i<=limit;i++)
{
if (!prime[i]) p[++tot]=i;
for(ll j=1;j<=tot&&i*p[j]<=limit;j++)
{
prime[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
}
int main()
{
scanf("%d",&n);
calc_prime(300);
for(int i=2;i<=300;i++)
{
for(int j=1;j<=tot;j++)
{
sum[i][j]=0;
int x=i;
while(x%p[j]==0) sum[i][j]++,x/=p[j];
sum[i][j]+=sum[i-1][j];
}
}
for(int i=1;i<=tot;i++) ans[i]=sum[n-2][i];
int s=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
if (n!=1&&d[i]==0) {printf("0");return 0;}
s+=d[i]-1;
}
if (s!=n-2) printf("0");
else
{
ll f=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=tot;j++)
ans[j]-=sum[d[i]-1][j];
for(int i=1;i<=tot;i++)
for(int j=1;j<=ans[i];j++)
f*=p[i];
printf("%lld",f);
}
return 0;
}