您的位置:首页 > Web前端

【prufer编码】BZOJ1211 [HNOI2004]树的计数

2015-06-22 19:27 316 查看

Description

  给定一棵树每个节点度的限制为di,求有多少符合限制不同的树。

Solution

  发现prufer码和度数必然的联系

  prufer码一个点出现次数为它的度数-1

  我们依然可以把树转成序列进行处理

  只是每个元素出现次数受到了限制

  于是就是有重复元素的排列问题了

  公式很好推

Code

  特殊情况判一判

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=155;

int dy[maxn],pri[maxn];
int tot[maxn],cnt;
int d[maxn],n,sum;

int getpri(){
for(int i=2;i<=n;i++){
if(!dy[i]) pri[++cnt]=i,dy[i]=cnt;
for(int j=1;j<=cnt&&i*pri[j]<=n;j++){
dy[pri[j]*i]=j;
if(i%pri[j]==0) break;
}
}
}

int add(int x,int k){
while(x!=1){
tot[dy[x]]+=k;
x/=pri[dy[x]];
}
}

ll pow(ll x,ll k){
ll ret=1;
for(int i=k;i;i>>=1,x=x*x)
if(i&1) ret=ret*x;
return ret;
}

int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&d[i]),sum+=d[i];
if(sum!=2*n-2){
printf("0\n");
return 0;
}
if(n==1){
printf("1\n");
return 0;
}

getpri();

for(int i=1;i<=n-2;i++) add(i,1);
for(int i=1;i<=n;i++)
if(!d[i]){
printf("0\n");
return 0;
}
else for(int j=1;j<d[i];j++) add(j,-1);

ll ans=1;
for(int i=1;i<=cnt;i++)
ans=ans*pow(1ll*pri[i],tot[i]);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: