【题目描述】
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
【题解】
每个prufer序列对应一棵树。
每个点在prufer序列中出现的次数=度数-1,组合数计算即可。
记得特判 n==1 的情况。
/* --------------
user Vanisher
problem bzoj-1005 && bzoj-1211
----------------*/
# include <bits/stdc++.h>
# define N 1010
# define MN 5010
using namespace std;
int a[N],cnt,n,inc[N],num[N][N],p[N],pnum,now;
struct number{
int num[MN];
}t,x,ans;
number operator *(number x, number y){
memset(t.num,0,sizeof(t.num));
for (int i=1; i<=x.num[0]; i++)
for (int j=1; j<=y.num[0]; j++)
t.num[i+j-1]+=x.num[i]*y.num[j];
t.num[0]=x.num[0]+y.num[0]-1; int i;
for (i=1; i<=t.num[0]||t.num[i]!=0; i++)
t.num[i+1]+=t.num[i]/10, t.num[i]%=10;
t.num[0]=i-1;
return t;
}
number mypow(int xx, int y){
memset(x.num,0,sizeof(x.num));
while (xx>0){
x.num[0]++;
x.num[x.num[0]]=xx%10;
xx/=10;
}
number i=x;
x.num[0]=1; x.num[1]=1;
while (y>0){
if (y%2==1) x=x*i;
i=i*i;
y/=2;
}
return x;
}
void pre(int n){
for (int i=2; i<=n; i++){
int j=i;
for (int k=2; k*k<=j; k++)
while (j%k==0){
num[i][k]++;
j/=k;
}
if (j!=1) num[i][j]++;
if (j==i) p[++pnum]=i;
}
}
int C(int n, int m){
for (int i=n; i>=n-m+1; i--) inc[i]++;
for (int i=1; i<=m; i++) inc[i]--;
}
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int main(){
n=read();
pre(n);
ans.num[0]=1, ans.num[1]=1;
for (int i=1; i<=n; i++){
a[i]=read();
if (a[i]==0&&n!=1){
puts("0");
return 0;
}
if (a[i]>0) now=now+(a[i]-1);
}
if (n==1&&a[1]==0) {
puts("1");
return 0;
}
if (now!=n-2){
puts("0");
return 0;
}
if (now>n-2)
printf("%d\n",0);
else{
now=n-2, cnt=n;
for (int i=1; i<=n; i++){
if (a[i]>0){
cnt--;
C(now,a[i]-1);
now=now-(a[i]-1);
}
}
for (int i=1; i<=n; i++){
int tmp=inc[i]; inc[i]=0;
for (int j=1; j<=pnum; j++)
inc[p[j]]+=num[i][p[j]]*tmp;
}
for (int i=1; i<=pnum; i++)
ans=ans*mypow(p[i],inc[p[i]]);
ans=ans*mypow(cnt,now);
for (int i=ans.num[0]; i>=1; i--)
printf("%d",ans.num[i]);
printf("\n");
}
return 0;
}