【prufer编码】BZOJ1211 [HNOI2004]树的计数
Description
给定一棵树每个节点度的限制为di,求有多少符合限制不同的树。
Solution
发现prufer码和度数必然的联系
prufer码一个点出现次数为它的度数-1
我们依然可以把树转成序列进行处理
只是每个元素出现次数受到了限制
于是就是有重复元素的排列问题了
公式很好推
Code
特殊情况判一判
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int maxn=155; 7 8 int dy[maxn],pri[maxn]; 9 int tot[maxn],cnt; 10 int d[maxn],n,sum; 11 12 int getpri(){ 13 for(int i=2;i<=n;i++){ 14 if(!dy[i]) pri[++cnt]=i,dy[i]=cnt; 15 for(int j=1;j<=cnt&&i*pri[j]<=n;j++){ 16 dy[pri[j]*i]=j; 17 if(i%pri[j]==0) break; 18 } 19 } 20 } 21 22 int add(int x,int k){ 23 while(x!=1){ 24 tot[dy[x]]+=k; 25 x/=pri[dy[x]]; 26 } 27 } 28 29 ll pow(ll x,ll k){ 30 ll ret=1; 31 for(int i=k;i;i>>=1,x=x*x) 32 if(i&1) ret=ret*x; 33 return ret; 34 } 35 36 int main(){ 37 scanf("%d",&n); 38 for(int i=1;i<=n;i++) 39 scanf("%d",&d[i]),sum+=d[i]; 40 if(sum!=2*n-2){ 41 printf("0\n"); 42 return 0; 43 } 44 if(n==1){ 45 printf("1\n"); 46 return 0; 47 } 48 49 getpri(); 50 51 for(int i=1;i<=n-2;i++) add(i,1); 52 for(int i=1;i<=n;i++) 53 if(!d[i]){ 54 printf("0\n"); 55 return 0; 56 } 57 else for(int j=1;j<d[i];j++) add(j,-1); 58 59 ll ans=1; 60 for(int i=1;i<=cnt;i++) 61 ans=ans*pow(1ll*pri[i],tot[i]); 62 printf("%lld\n",ans); 63 return 0; 64 }