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
2 2
【样例输入2】
2 3
【样例输入3】
3 5
Sample Output
【样例输出1】3
【样例输出2】
21
【样例输出2】
58871587162270592645034001
-----------------------------------------------------------------------------------------------
感觉这道题想树形dp+组合数。。纠结了一会没想到简单点的写法
于是参照了大神们的题解。。。发现这道题是如此。。。。
设dp[i]为深度不大于i的严格n元树的个数。自然dp[0]=1,答案就为dp[d]-dp[d-1]。
假设我们已知dp[i-1],那么深度不大于i的树就相当于多出了一个根节点,其每一个儿子(共n个儿子)都是一颗深度不大于i-1的树。
那么dp[i]=dp[i-1]^n+1(还有没有儿子的情况),直接线性递推就可以得到答案了。
这里还有一个坑点:当d==0的时候,ans直接=dp[0]而不是dp[0]-dp[0-1];这里数组超界不一定会RE,而有可能wa。。。我就在这被坑了好久
另一种推法参见这位神牛的题解: http://hi.baidu.com/gzh19950711/item/c3ac0f0b0ad3b0c190571881
这题另外的考点在于高精度和快速幂。。。(其实不加快速幂大概也能过吧- -)
代码:
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int M=1000;
struct bign
{
int num[1000+10],len;
bign()
{
memset(num,0,sizeof(num));
len=1;
}
bign operator =(int x)
{
len=0;
while(x)
{
num[len++]=x%M;
x/=M;
}
if(len==0)len=1;
return *this;
}
bign operator =(const bign &b)
{
len=b.len;
for(int i=0;i<len;i++)num[i]=b.num[i];
return *this;
}
bign operator +(int x)
{
bign c;
c=*this;
c.num[0]=c.num[0]+x;
int temp=c.num[0]/M;
c.num[0]=c.num[0]%M;
int i=1;
while(temp)
{
c.num[i]=c.num[i]+temp;
temp=c.num[i]/M;
c.num[i]=c.num[i]%M;
i++;
}
if(i>c.len)c.len=i;
return c;
}
bign operator *(int x)
{
bign c;
c.len=len;
for(int i=0;i<c.len;i++)c.num[i]=num[i]*x;
int temp=0;
for(int i=0;i<c.len;i++)
{
c.num[i]+=temp;
temp=c.num[i]/M;
c.num[i]=c.num[i]%M;
if(i==c.len-1&&temp!=0)c.len++;
}
while(c.len&&c.num[c.len-1]==0)c.len--;
if(c.len==0)c.len=1;
return c;
}
bign operator *(const bign &b)
{
bign c;
c.len=len+b.len-1;
for(int i=0;i<len;i++)
{
for(int j=0;j<b.len;j++)
{
c.num[i+j]+=num[i]*b.num[j];
}
}
int temp=0;
for(int i=0;i<c.len;i++)
{
c.num[i]+=temp;
temp=c.num[i]/M;
c.num[i]=c.num[i]%M;
if(i==c.len-1&&temp!=0)c.len++;
}
while(c.len&&c.num[c.len-1]==0)c.len--;
if(c.len==0)c.len=1;
return c;
}
bign operator -(const bign &b)
{
bign c;
c.len=len;
int temp=0;
for(int i=0;i<c.len;i++)
{
if(num[i]-temp<b.num[i])
{
c.num[i]=num[i]-temp+M-b.num[i];
temp=1;
}
else
{
c.num[i]=num[i]-temp-b.num[i];
temp=0;
}
}
while(c.len&&c.num[c.len-1]==0)c.len--;
if(c.len==0)c.len=1;
return c;
}
void print()
{
printf("%d",num[len-1]);
for(int i=len-2;i>=0;i--)
{
printf("%03d",num[i]);
}
printf("\n");
}
};
int n,d;
bign qpow(const bign &x,int c)
{
bign ret;
if(c==0)return ret=1;
if(c==1)return ret=x;
ret=qpow(x,c/2);
ret=ret*ret;
if(c&1)ret=ret*x;
return ret;
}
bign dp[20];
bign ans;
int main()
{
scanf("%d%d",&n,&d);
dp[0]=1;
for(int i=1;i<=d;i++)
{
dp[i]=qpow(dp[i-1],n)+1;
}
if(d>0)ans=dp[d]-dp[d-1];
else ans=dp[d];
ans.print();
return 0;
}