[Spoj]严格n元树(dp)

这篇博客探讨了严格n元树的概念,即每个非叶节点恰好有n个子节点,以及如何计算深度为d的此类树的数量。通过动态规划方法,可以有效地找出满足条件的树的总数。示例输入和输出展示了问题的具体形式和预期解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如有错误,请留言提醒,不要坑到小朋友

Description

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

Input

仅包含两个整数n,d(0 < n < = 32,0 <= d <= 16)。输入数据保证你不需要考虑某一层多于1024个节点的树(nd<=1024)。提示:答案保证不超过200位十进制数。 

Output

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

Sample Input

【样例输入1】
    2  2
【样例输入2】
   2 4

Sample Output

【样例输出1】
   3 
【样例输出2】
  651
f[i]代表深度为i的情况下n元树的数目
tot[i]代表深度小于等于i的情况下n元树的数目
f[i]=tot[i-1]^n-tot[i-2]^n
为什么要减呢
因为tot[i-1]^n包括了最深度小于i-1的情况;
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<climits>
#include<cctype>
#include<string>
#define maxn 33
using namespace std;
namespace ljq{
	struct bign{
		#define max(a,b) ((a)>(b)?(a):(b))
		static const int maxlen=5000,limit=10000,width=4;
		int len,bit[maxlen];
		void clearbit(){memset(bit,0,sizeof(bit));}
		void delete0(){for(;!bit[len-1]&&len>1;--len);}
		int& operator[](int p){return bit[p];}
		bign(int p=0){*this=p;}
		bign& operator=(int p){
			clearbit();
			len=p?0:1;
			for(;p;p/=limit)bit[len++]=p%limit;
			return *this;
		}
		bign(const char*p){*this=p;}
		bign& operator=(const char*p){
			clearbit();
			for(int i=strlen(p)-1;i>=0;i-=4){
				int now=0;
				for(int j=max(0,i-width+1);j<=i;j++)now=now*10+p[j]-'0';
				bit[len++]=now;
			}
			return *this;
		}
		bign& operator+=(bign b){
			len=max(len,b.len)+1;
			for(int i=0;i<len;i++)bit[i]+=b[i],bit[i+1]+=bit[i]/limit,bit[i]%=limit;
			delete0();
			return *this;
		}
		bign& operator-=(bign b){
			for(int i=0;i<len;i++){bit[i]-=b[i];if(bit[i]<0)bit[i]+=limit,bit[i+1]--;}
			delete0();
			return *this;
		}
		bign& operator*=(bign b){
			bign a=*this;
			len=a.len+b.len;
			clearbit();
			for(int i=0;i<a.len;i++)
				for(int j=0;j<b.len;j++)
					bit[i+j]+=a.bit[i]*b.bit[j],bit[i+j+1]+=bit[i+j]/limit,bit[i+j]%=limit;
			delete0();return *this;
		}
		bign& operator/=(int b){
			for(int i=len-1;i>0;--i)bit[i-1]+=limit*(bit[i]%b),bit[i]/=b;bit[0]/=b;
			delete0();return *this;
		}
		bool operator<(bign b)const{
			if(len>b.len)return 0;
			if(len<b.len)return 1;
			for(int i=len-1;i>=0;i--)
				if(bit[i]!=b[i])return bit[i]<b[i];
			return bit[0]<b[0];
		}
		bool operator==(bign b)const{return !(*this<b)&&!(b<*this);}
		bool operator!=(bign b)const{return !(*this==b);}
		bool operator>(bign b)const{return b<*this;}
		bool operator<=(bign b)const{return !(*this>b);}
		bool operator>=(bign b)const{return !(*this<b);}
	};
	bign operator+(bign a,bign b){return a+=b;}
	bign operator-(bign a,bign b){return a-=b;}
	bign operator*(bign a,bign b){return a*=b;}
	bign operator/(bign a,int b){return a/=b;}
	istream& operator>>(istream &is,bign &p){
		string s;
		is>>s;p=s.c_str();
		return is;
	}
	ostream& operator<<(ostream &os,bign &p){
		os.fill('0');os<<p.bit[p.len-1];
		for(int i=p.len-2;i>=0;i--){os.width(bign::width);os<<p.bit[i];}
		return os;
	}
	bign sqrt(bign x){
		bign l=1,r=x;
		while(l<=r){
			bign mid=(l+r)/2;
			if(x<mid*mid)r=mid-1;else l=mid+1;
		}
		return r;
	}
}using ljq::bign;
bign f[maxn],tot[maxn];
int n,m;
bign ksm(bign a,int b){
	bign t,y;
	t=1;y=a;
	while(b){
		if(b&1)t=t*y;
		y=y*y;
		b=b>>1;
	}
	return t;
}
void init(){
	tot[0]=f[0]=1;
	f[1]=1;
	tot[1]=2;
	for(int j=2;j<=m;j++){
		f[j]=ksm(tot[j-1],n)-ksm(tot[j-2],n);
		tot[j]=tot[j-1]+f[j];
	}			
}
int main(){
	scanf("%d%d",&n,&m);
	init();
	cout<<f[m]<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值