1. 程式人生 > >BZOJ1005:[HNOI2008]明明的煩惱(組合數學,Prufer)

BZOJ1005:[HNOI2008]明明的煩惱(組合數學,Prufer)

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

Solution

屠龍寶刀點選再送

要寫高精度和質因數分解。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define N (3009)
 7 #define MAX_L 10009
 8 using namespace std;
 9 
10 int n,m,rem,d,ans[N],cnt[N];
11 
12 void Divide(int x,int opt)
13 { 14 for (int i=2; i<=sqrt(x); ++i) 15 while (x%i==0) x/=i,cnt[i]+=opt; 16 if (x>1) cnt[x]+=opt; 17 } 18 19 void Mul(int *a,int b) 20 { 21 int g=0; 22 for (int i=1; i<=a[0]; ++i) 23 a[i]=a[i]*b+g,g=a[i]/10,a[i]%=10; 24 while (g) a[0]++,a[a[0]]=g%10,g/=10
; 25 } 26 27 int main() 28 { 29 ans[0]=ans[1]=1; 30 scanf("%d",&n); rem=n-2; 31 for (int i=1; i<=n-2; ++i) Divide(i,1); 32 for (int i=1; i<=n; ++i) 33 { 34 scanf("%d",&d); 35 if (!d && n>1) {puts("0"); return 0;} 36 if (d==-1) {++m; continue;} 37 if ((rem=rem-(d-1))<0) {puts("0"); return 0;} 38 for (int j=1; j<=d-1; ++j) Divide(j,-1); 39 } 40 if (n==1) 41 { 42 if (d==-1 || d==0) puts("1"); 43 else puts("0"); 44 return 0; 45 } 46 for (int i=1; i<=rem; ++i) Divide(i,-1); 47 for (int i=1; i<=rem; ++i) Divide(m,1); 48 for (int i=1; i<=n; ++i) 49 for (int j=1; j<=cnt[i]; ++j) 50 Mul(ans,i); 51 for (int i=ans[0]; i>=1; --i) 52 printf("%d",ans[i]); 53 }