SCOI2003【严格n元树】

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元树的数目。


我是先从简单的情况入手,就讨论完全二叉树的个数,得到是2^2n  -1
然后又想完全三叉树的个数
然后就陷入了一个误区:总是想考虑下面的叶子节点该怎么加才满足,使劲推公式尽量往组合数上靠,结果憋了半天没搞出来。
然后题解是dp:
定义f[i]表示深度为i的n元树的个数,发现这个并不好直接转移
因为组合的时候不一定是一些i-1深度的n元树。
需要转化:
改为求f[i]的前缀和s[i]

s[i]表示深度不大于i的n元树的个数.
这里转移不是考虑怎么在下面加节点,而是添一个根:
s[i-1]种不同的n元树,在添一个根时候的状态是n棵不同的不超过i-1深度的树排在一起,也有可能为空.
s[i]=s[i-1]^n +1(我们考虑树不为空的情况,但组合的时候可能只有根,而s[i-1]状态里没有空的子树)
然后答案就是s[i]-s[i-1]了。

这里吸取一个教训,不要局限于题意顺序,逆向思维。
#include
#include
#include
#include
#include
#include
#include
#define base 10000
#define maxlen 101
#define get(x) (x-'0')
using namespace std;
int n,d;
const int maxn=20;
struct bign
{
	int sign,len;
	int c[maxlen];
	bign()
	{
		sign=0;
		len=1;
		memset(c,0,sizeof(c));
	}
	void Printf()
	{
		if(sign)printf("-");
		printf("%d",c[len]);
		for(int i=len-1;i>=1;i--)printf("%04d",c[i]);
		printf("\n");
	}
	void zero()
	{
		while(len-1&&!c[len])len--;
	}
	void writen(char *s)
	{
		int l=strlen(s),lim=0,k=1;
		if(s[0]=='-')
		{
			sign=1;
			lim=1;
		}
		for(int i=l-1;i>=lim;i--)
		{
			c[len]+=get(s[i])*k;
			k*=10;
			if(k==base)
			{
				len++;
				k=1;
			}
		}
	}
	void Read()
	{
		char s[maxlen*base];
		scanf("%s",s);
		writen(s);
	}
	bool operator <(const bign &b)
	{
		if(len!=b.len)return len=1;i--)
		{
			if(c[i]!=b.c[i])return c[i]>=1;
			r=r*r;
		}
		return res;
	}
	bign operator -(const bign &b)
	{
		bign r=*this;
		bign y=b;
		if(r


你可能感兴趣的:(bzoj,图上计数)