「BZOJ1005」[HNOI2008] 明明的烦恼
先放几个prufer序列的结论:
Prufer序列是一种对有标号无根树的编码,长度为节点数-2。
具体存在无根树转化为prufer序列和prufer序列转化为无根树两种操作:
无根树转化为prufer序列 1、找到编号最小的度数为1的点 2、删除该节点并在序列中添加与该节点相连的节点的编号 3、重复1,2操作,直到整棵树只剩下两个节点
prufer序列转化为无根树 设prufer序列为M,另一个集合G={1,2…n} 每次提取M中最靠前的元素u与G中不存在与M且最靠前的元素v,将u与v连边,分别在两个集合中删除u、v。 最后G中剩下两个元素,将这两个点连边。
Prufer序列中某个编号出现的次数等于这个编号的节点在无根树中的度数-1 。 一棵n个节点的无根树唯一地对应了一个长度为n-2的数列,数列中的每个数都在1到n的范围内
有关性质的应用 n个点构成的无根树的个数: $n^(n-2)$ 确定n个点度数分别为d1,d2…时无根树个数: $(n-2)!/((d1-1)!*(d2-1)!*…)$ n个点的
有标号有根树的个数: $n*n^{n-2}=n^{n-1}$
然后看这个题:
有某些点知道度数,那么先把这些点放到prufer序列中,设num为度数大于0的点数,fnum为已知度数的点出现次数总和,
方案数C_{n-2}^{fnum}*(n-2)!/((d1-1)!*(d2-1)!*…),然后把剩下的序列填满,每个序列有n-num种情况,乘法计数原理成起来即${n-num}^{n-2-fnum}$,最后将两部分乘起来即可。(这个题也用到了高精……)
1 #include<algorithm> 2 #include<cstring> 3 #include<iostream> 4 #include<cstdio> 5 using namespace std; 6 #define ma(x) memset(x,0,sizeof(x)) 7 int n,d[1010],num,fnum; 8 struct sz 9 { 10 int a[20000]; 11 }a; 12 sz mul(sz &a,int b) 13 { 14 sz c;ma(c.a); 15 c.a[0]=a.a[0]; 16 for(int i=1;i<=a.a[0];i++) 17 c.a[i]=a.a[i]*b; 18 for(int i=1;i<=c.a[0];i++) 19 if(c.a[i]>=10) 20 { 21 c.a[i+1]+=c.a[i]/10; 22 c.a[i]%=10; 23 if(i==c.a[0])c.a[0]++; 24 } 25 return c; 26 } 27 sz div(sz &a,int b) 28 { 29 sz ans;ma(ans.a); 30 int yu=0; 31 for(int i=1;i<=a.a[0];i++) 32 { 33 yu=yu*10+a.a[i]; 34 if(yu/b>0) 35 { 36 ans.a[++ans.a[0]]=yu/b; 37 yu%=b; 38 } 39 else if(ans.a[0])ans.a[0]++; 40 } 41 return ans; 42 } 43 void print(sz &a) 44 { 45 for(int i=1;i<=a.a[0];i++)cout<<a.a[i]; 46 puts(""); 47 } 48 bool cmp(int a,int b){return a>b;} 49 signed main() 50 { 51 cin>>n; 52 for(int i=1;i<=n;i++) 53 { 54 cin>>d[i]; 55 if(d[i]>-1)num++; 56 if(d[i]>=2)fnum+=d[i]-1; 57 if((d[i]==0&&n!=1)||d[i]>=n||(d[i]!=0&&n==1)){puts("0");return 0;} 58 } 59 a.a[0]=a.a[1]=1; 60 for(int i=2;i<=n-2;i++)a=mul(a,i);//(n-2)! 61 sort(d+1,d+n+1,cmp); 62 reverse(a.a+1,a.a+a.a[0]+1); 63 for(int i=1;i<=num;i++)//(d[i]-1)! 64 for(int j=2;j<d[i];j++) 65 a=div(a,j); 66 for(int i=2;i<=n-2-fnum;i++)a=div(a,i);//(n-2-fnum)! 67 reverse(a.a+1,a.a+a.a[0]+1); 68 for(int i=1;i<=n-2-fnum;i++) 69 a=mul(a,n-num); 70 reverse(a.a+1,a.a+a.a[0]+1); 71 print(a); 72 }
波澜前,面不惊。