题意
一个有 (n) 个节点的树,设它的节点分别为 (v_1,v_2,dots,v_n),已知第 (i) 个节点 (v_i) 的度数为 (d_i),问满足这样的条件的不同的树有多少棵。
(1leq n leq 150)
分析
根据 ( ext{prufer}) 序列的性质,每棵树对应序列的长度均为 (n-2),每个编号 (i) 会在序列中出现 (d_i-1) 次。结合可重集合的排列公式,可得最终结果为:
[ans=frac{(n-2)!}{prod_{i=1}^{n}(d_i-1)!}
]
同时,考虑到无解的情况:
- 出现点的度大于 (n-1) 的情况
- 当 (n>1) 时,出现点的度为 (0)
- 各点的度数之和不等于 (2(n-1)) ,即 (sum{(d_i-1)} eq n-2)
使用高精度或者 ( ext{python}),即可算出。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll scale=100000;
struct number
{
int maxn=1010;
ll di[1010];
void clc()
{
for(int i=0;i<maxn;i++) di[i]=0;
}
int comp(const number &b)const//比较大小
{
if(di[0]>b.di[0]) return 1;
if(di[0]<b.di[0]) return -1;
for(int i=di[0];i>=1;i--)
{
if(di[i]>b.di[i]) return 1;
if(di[i]<b.di[i]) return -1;
}
return 0;
}
number operator - (const number &b)const
{
number res,a;
for(int i=0;i<=di[0];i++) a.di[i]=di[i];
for(int i=1;i<=a.di[0];i++)
{
if(a.di[i]<b.di[i])
{
a.di[i]+=scale;
a.di[i+1]--;
}
res.di[i]=a.di[i]-b.di[i];
}
res.di[0]=a.di[0];
ll &p=res.di[0];
while(res.di[p]==0&&p>=0) p--;
return res;
}
number operator *(const number &b)const//高精度乘高精度
{
number res;
for(int i=1;i<=di[0];i++)
{
for(int j=1;j<=b.di[0];j++)
res.di[i+j-1]=di[i]*b.di[j];
}
res.di[0]=di[0]+b.di[0];
for(int i=1;i<=res.di[0];i++)
{
res.di[i+1]+=res.di[i]/scale;
res.di[i]=res.di[i]%scale;
}
ll &p=res.di[0];
while(res.di[p]==0&&p>=0) p--;
return res;
}
number operator / (const number &b)const //高精度除高精度,默认大于
{
number res,a;
res.clc();
a.clc();
for(int i=0;i<=di[0];i++) a.di[i]=di[i];
int f=comp(b);
while(f>=0)
{
a=a-b;
res.di[1]++;
int p=1;
while(res.di[p]>0)
{
res.di[p+1]+=res.di[p]/scale;
res.di[p]=res.di[p]%scale;
p++;
}
res.di[0]=p;
f=a.comp(b);
}
//最终a中存余数
ll &p=res.di[0];
while(res.di[p]==0&&p>=0) p--;
return res;
}
void print()
{
printf("%lld",di[di[0]]);
int d=5;//根据具体的进制确定
for(int i=di[0]-1;i>=1;i--)
printf("%.5lld",di[i]);
printf("
");
}
};
void mul(number &a,int b)
{
for(int i=1;i<=a.di[0];i++)
a.di[i]*=b;
for(int i=1;i<=a.di[0]+10;i++)
{
a.di[i+1]+=a.di[i]/scale;
a.di[i]=a.di[i]%scale;
}
a.di[0]+=10;
ll &p=a.di[0];
while(a.di[p]==0&&p>=0) p--;
}
int main()
{
int n,d,flag=1,tol=0;
scanf("%d",&n);
number x,y;
x.clc();
y.clc();
x.di[0]=y.di[0]=1;
x.di[1]=y.di[1]=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&d);
tol+=d;
if(d>n-1||(n>1&&d==0)) flag=0;
for(int j=1;j<d;j++)
mul(y,j);
}
if(tol!=2*(n-1)) flag=0;
if(flag==0)
{
printf("0
");
return 0;
}
//y.print();
for(int i=1;i<n-1;i++)
mul(x,i);
//x.print();
number ans=x/y;
ans.print();
return 0;
}