「BZOJ1005」[HNOI2008] 明明的烦恼

「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 }
View Code

 

 

 

posted @ 2019-07-22 06:30  Al_Ca  阅读(153)  评论(1编辑  收藏  举报
ヾ(≧O≦)〃嗷~