【BZOJ 1211】HNOI2004]樹的計數(組合數學+Purfer序列)
阿新 • • 發佈:2018-12-11
1211: [HNOI2004]樹的計數 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3149 Solved: 1181 [Submit][Status][Discuss] Description
一個有n個結點的樹,設它的結點分別為v1, v2, …, vn,已知第i個結點vi的度數為di,問滿足這樣的條件的不同的樹有多少棵。給定n,d1, d2, …, dn,程式設計需要輸出滿足d(vi)=di的樹的個數。 Input
第一行是一個正整數n,表示樹有n個結點。第二行有n個數,第i個數表示di,即樹的第i個結點的度數。其中1<=n<=150,輸入資料保證滿足條件的樹不超過10^17個。 Output
輸出滿足條件的樹有多少棵。 Sample Input 4
2 1 2 1
Sample Output 2
在寫這道題之前我們先了解一下什麼叫做Purfer序列。 Purfer序列是通過尋找一棵樹最小的葉節點,把與這個葉節點相連的非根節點加入到陣列中,並刪除,直到剩下兩個點為止, 這n-2個數就是Purfer序列,每顆樹只有一個Purfer序列。並且每個點最多在Purfer序列種出現次。 因此最後的答案為 。 在這個過程中,乘法會爆long long,因此我們需要進行質因數分解優化。 把參與運算的每個數質因數分解,除法的時候直接消去即可。 最終在把剩下的數乘起來。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6+10; const int INF = 0x3f3f3f3f; typedef long long ll; ll a[maxn]; ll cnt[maxn]; void solve(ll n,ll kk){ for(ll i=2;i*i<=n;i++){ while(n%i==0){ cnt[i]+=kk; n/=i; } } cnt[n]+=kk; return ; } int main(){ ll n; cin>>n; ll sum=0; for(ll i=1;i<=n;i++){ cin>>a[i]; sum+=a[i]; } for(ll i=1;i<=n;i++){ if(!a[i]&&n>1){ cout<<0<<endl; return 0; } } if(sum!=2*n-2){ cout<<0<<endl; return 0; } if(n<=2){ cout<<1<<endl; return 0; } for(ll i=1;i<=n-2;i++){ solve(i,1); } ll ans=1; for(ll i=1;i<=n;i++){ for(ll j=2;j<a[i];j++){ solve(j,-1); } } for(ll i=1;i<=n;i++){ for(ll j=1;j<=cnt[i];j++){ ans*=i; } } cout<<ans<<endl; return 0; }