【BZOJ 1005】 1005: [HNOI2008]明明的烦恼 (prufer数列+高精度)

1005: [HNOI2008]明明的烦恼

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4981  Solved: 1941

Description

  自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?

Input

  第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

Output

  一个整数,表示不同的满足要求的树的个数,无解输出0

Sample Input

3
1
-1
-1

Sample Output

2

HINT

  两棵树分别为1-2-3;1-3-2

Source

 

 

【分析】

  先特判无解的情况。

  假设$sum=\sum(d[i]-1)|[d[i]!=-1]$

  $ss=\sum 1 [d[i]!=-1]$

  则$Ans=C_{n-2}^{sum}*\dfrac{sum!}{\Pi(d[i]-1)!}*(n-ss)^{n-2-sum}$

  即$Ans=\dfrac{(n-2)!}{(n-2-sum)!*\Pi(d[i]-1)!}*(n-ss)^{n-2-sum}$

  这些数值都不会超过n的,先手动消因子,然后Ans用高精度,就是高精乘单精。

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 1010
 8 #define mod 10000
 9 
10 int cnt[Maxn],d[Maxn];
11 
12 struct hugeint
13 {
14     int w[Maxn],l;
15     hugeint() {memset(w,0,sizeof(w));l=0;}
16     friend hugeint operator * (hugeint x,int y)
17     {
18         for(int i=0;i<=x.l;i++) x.w[i]*=y;
19         for(int i=0;i<=x.l;i++) x.w[i+1]+=x.w[i]/mod,x.w[i]%=mod;
20         while(x.w[x.l+1]!=0) x.w[x.l+2]+=x.w[x.l+1]/mod,x.w[++x.l]%=mod;
21         while(x.w[x.l]==0&&x.l>0) x.l--;
22         return x;
23     }
24 };
25 
26 void cal(int x,int y)
27 {
28     for(int i=2;i<=x*x;i++) if(x%i==0)
29     {
30         while(x%i==0) cnt[i]+=y,x/=i;
31     }
32     if(x!=1) cnt[x]+=y;
33 }
34 
35 int main()
36 {
37     int n;
38     scanf("%d",&n);
39     for(int i=1;i<=n;i++) scanf("%d",&d[i]);
40     if(n==1&&d[1]>0) printf("0\n");
41     else
42     {
43         int sum=0,ss=0;
44         for(int i=1;i<=n;i++) if(d[i]!=-1) sum+=d[i]-1,ss++;
45         else if(d[i]==0||d[i]>=n) {printf("0\n");return 0;}
46         if(sum>n-2) printf("0\n");
47         else
48         {
49             // for(int i=1;i<=n;i++) if(d[i]!=-1) d[i]--;
50             for(int i=1;i<=n;i++) cnt[i]=0;
51             for(int i=2;i<=n-2;i++) cal(i,1);
52             for(int i=2;i<=n-2-sum;i++) cal(i,-1);
53             for(int i=1;i<=n;i++) if(d[i]!=-1)
54             {
55                 for(int j=2;j<=d[i]-1;j++) cal(j,-1);
56             }
57             cal(n-ss,n-2-sum);
58             hugeint ans;ans.w[0]=1;
59             for(int i=2;i<=n;i++) while(cnt[i]--) ans=ans*i;
60             printf("%d",ans.w[ans.l]);
61             for(int i=ans.l-1;i>=0;i--) printf("%04d",ans.w[i]);printf("\n");
62         }
63     }
64     return 0;
65 }
View Code

 

2017-04-25 15:36:48

posted @ 2017-04-25 15:36 konjak魔芋 阅读(...) 评论(...) 编辑 收藏