Submit: 6539 Solved: 2558
[Submit][Status][Discuss]
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0
Sample Input
1
-1
-1
Sample Output
HINT
两棵树分别为1-2-3;1-3-2
首先要知道 Prufer数列 和 节点度数 这种东西,自行Google。
Plufer数列有一下性质:
1、可以表示为任意一个长度为n-2的数列
2、任意一点的度数为d[i],则该节点在数列中出现d[i]-1次
3、因此数列的总长度为:
[sum=sum _{i=1}^{n} (d[i]-1)]
得出这个总长度的前提是,所有度数已知,但题目并没有给出所有的度数。但是我们可以计算出已知n个点的度数,可以构造出多少种Prufer数列:
[frac{(n-2)!}{prod _{i-1}^{n}(d[i]-1)!}]
那么已知cnt个点的度数,可以构造出多少种Prufer数列呢?
[C_{n-2}^{sum} imes frac{sum!}{prod _{i-1}^{n}(d[i]-1)!}]
那么已知cnt个点的度数,n-cnt个点的度数未知,可以构造出多少种Prufer数列呢?
[ans=C_{n-2}^{sum} imesfrac{sum!}{prod _{i-1}^{n}(d[i]-1)!} imes(n-cnt)^{n-2-sum}]
最终可以化简得:
[ans=frac{(n-2)!}{(n-2-sum)!prod _{i-1}^{n}(d[i]-1)!} imes(n-cnt)^{n-2-sum}]
沿用了之前高精度乘除单精度的模板,减少代码量(明明是增加了)
虽说质因数分解更能显示bigger。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<iomanip> 6 using namespace std; 7 8 const int MAXN=1000; 9 const int DLEN=4; 10 const int WIDE=10000; 11 class BigNum 12 { 13 public: 14 int NUM[MAXN]; 15 int L; 16 bool flag; 17 BigNum(){memset(NUM,0,sizeof(NUM));L=1;flag=0;} 18 BigNum(const BigNum &T){memcpy(NUM,T.NUM,sizeof(NUM));L=T.L;flag=T.flag;} 19 BigNum(int n){memset(NUM,0,sizeof(NUM));NUM[0]=n;L=1;while(NUM[L-1]>=WIDE){NUM[L]+=NUM[L-1]/WIDE;NUM[L-1]%=WIDE;L++;}flag=0;} 20 }; 21 22 void Output(const BigNum T) 23 { 24 if(T.flag==1) cout<<'-'; 25 cout<<T.NUM[T.L-1]; 26 for(int i=T.L-2;i>=0;i--) 27 { 28 cout.width(DLEN); 29 cout.fill('0'); 30 cout<<T.NUM[i]; 31 } 32 } 33 34 BigNum Mult(const BigNum A,int B) 35 { 36 BigNum C(A); 37 int i,tmp,k=0; 38 for(i=0;i<C.L||k;i++) 39 { 40 tmp=C.NUM[i]*B+k; 41 k=tmp/WIDE; 42 C.NUM[i]=tmp%WIDE; 43 } 44 C.L=i; 45 return C; 46 } 47 48 BigNum Div(const BigNum A,int B) 49 { 50 BigNum C(A); 51 int k=0; 52 for(int i=C.L-1;i>=0;i--) 53 { 54 k=k*WIDE+C.NUM[i]; 55 C.NUM[i]=k/B; 56 k%=B; 57 } 58 while(C.NUM[C.L-1]==0) C.L--; 59 return C; 60 } 61 62 int n,sum,cnt; 63 int d[1005]; 64 bool flag; 65 BigNum ans(1); 66 67 int main() 68 { 69 scanf("%d",&n); 70 for(int i=1;i<=n;i++) 71 { 72 scanf("%d",&d[i]); 73 if(d[i]==0||d[i]>n-1) flag=1; 74 if(d[i]==-1) continue; 75 sum+=d[i]-1; 76 cnt++; 77 } 78 if(n==1) 79 { 80 if(d[1]==0||d[1]==-1) printf("1 "); 81 else printf("0 "); 82 return 0; 83 } 84 if(n==2) 85 { 86 if((d[1]==0||d[1]>1)&&(d[2]==0||d[2]>1)) printf("1 "); 87 else printf("0 "); 88 return 0; 89 } 90 if(flag) 91 { 92 printf("0 "); 93 return 0; 94 } 95 for(int i=n-1-sum;i<=n-2;i++) 96 ans=Mult(ans,i); 97 for(int i=1;i<=n-2-sum;i++) 98 ans=Mult(ans,n-cnt); 99 for(int i=1;i<=cnt;i++) 100 for(int j=1;j<=d[i]-1;j++) 101 ans=Div(ans,j); 102 Output(ans); 103 return 0; 104 }