【题目描述】
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为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 ",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(" "); } return 0; }