BZOJ1005:[HNOI2008]明明的煩惱(組合數學,Prufer)
阿新 • • 發佈:2019-01-06
Description
自從明明學了樹的結構,就對奇怪的樹產生了興趣......給出標號為1到N的點,以及某些點最終的度數,允許在任意兩點間連線,可產生多少棵度數滿足要求的樹?
Input
第一行為N(0 < N < = 1000),
接下來N行,第i+1行給出第i個節點的度數Di,如果對度數不要求,則輸入-1
Output
一個整數,表示不同的滿足要求的樹的個數,無解輸出0
Sample Input
31
-1
-1
Sample Output
2HINT
兩棵樹分別為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 }