1. 程式人生 > >【BZOJ 1005】 1005: [HNOI2008]明明的煩惱 (prufer數列+高精度)

【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