1089: [SCOI2003]严格n元树

来源:互联网 发布:深圳网络优化 编辑:程序博客网 时间:2024/05/16 16:21


Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 1509  Solved: 746
[Submit][Status][Discuss]

Description

  如果一棵树的所有非叶节点都恰好有n个儿子,那么我们称它为严格n元树。如果该树中最底层的节点深度为d
(根的深度为0),那么我们称它为一棵深度为d的严格n元树。例如,深度为2的严格2元树有三个,如下图:

  给出n, d,编程数出深度为d的n元树数目。

Input

  仅包含两个整数n, d( 0   <   n   <   =   32,   0  < =   d  < = 16)

Output

  仅包含一个数,即深度为d的n元树的数目。

Sample Input

【样例输入1】
2 2

【样例输入2】
2 3

【样例输入3】
3 5

Sample Output

【样例输出1】
3

【样例输出2】
21

【样例输出2】
58871587162270592645034001

题解:
f[i]代表深度<=i的严格n元树的个数
f[d]-f[d-1]就是答案
f[i],由f[i-1]递推来,考虑新加一个根节点,然后根节点有n个子节点,每
个子节点都可以建一颗深度<=i-1的树,那么每个子节点都有f[i-1]种选法,
那么n个子节点就有f[i-1]^n选法。以上至少深度为1,毕竟有个根节点,加上深度为0的情况
那么f[i]:=(f[i-1]^n)+1;
注意d=0时要特判。


#include<cstdio>
#include<cstring>
using namespace std;
#define mod 10000
struct node
{
int a[5100],len;
node()
{
memset(a,0,sizeof(a));len=1;
}
}f[40];
node chengfa(node n1,node n2)
{
node no; no.len=n1.len+n2.len-1;
for(int i=1;i<=n1.len;i++)for(int j=1;j<=n2.len;j++) no.a[i+j-1]+=n1.a[i]*n2.a[j];
for(int i=1;i<=no.len;i++)
{
no.a[i+1]+=no.a[i]/mod;
no.a[i]%=mod;
}
int i=no.len;
while(no.a[i+1]>0)
{
i++;
no.a[i+1]+=no.a[i]/mod;
no.a[i]%=mod;
}
no.len=i;
return no;
}
node jianfa(node no,node n2)
{


for(int i=1;i<=no.len;i++)no.a[i]-=n2.a[i];
for(int i=1;i<=no.len;i++)
{
if(no.a[i]<0) no.a[i]+=mod,no.a[i+1]-=1;
}
int i=no.len;
while(i>1&&no.a[i]==0)i--;
no.len=i;
return no;
}
node _pow(node no,int b)
{
node ans;ans.a[1]=1;ans.len=1;
while(b)
{
if(b&1) ans=chengfa(ans,no);
no=chengfa(no,no);
b=b/2;
}
return ans;
}
int main()
{
int n,d;
scanf("%d%d",&n,&d);if(d==0) { printf("1\n");return 0;}
memset(f,0,sizeof(f));
f[0].a[1]=1;f[0].len=1;
f[1].a[1]=2;f[1].len=1;
for(int i=2;i<=d;i++)
{
f[i]=_pow(f[i-1],n);
f[i].a[1]++;
for(int i=1;i<=f[i].len;i++) if(f[i].a[i]>=mod) f[i].a[i]-=mod,f[i].a[i+1]++;
if(f[i].a[f[i].len+1]>0)f[i].len++;
}
node ans=jianfa(f[d],f[d-1]);
printf("%d",ans.a[ans.len]);
for(int i=ans.len-1;i>=1;i--) printf("%04d",ans.a[i]);printf("\n");
return 0;
}

1 0
原创粉丝点击