51nod 1412 AVL树的种类(经典dp)

时间:2024-04-16 16:34:21

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1412

题意:

51nod 1412 AVL树的种类(经典dp)

思路:

经典dp!!!可惜我想不到!!

$dp[i][k]$表示i个结点,最大深度为k的形态数。

它的转移方程就是:

dp[i][k] += dp[i -  - j][k - ] * dp[j][k - ]
dp[i][k] += * dp[i - - j][k - ] * dp[j][k - ]

j是右子树结点个数,如果除去根结点,是不是可以分为左右两棵子树,那这里就是应用了乘法原理。

分为两种情况的原因是:①左右两棵子树的深度相同 ②左右两棵子树的深度差1,这里左子树深度小还是右子树深度小都是一样的,所以直接乘2即可。

 #include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pll;
const int inf = 0x3f3f3f3f;
const int maxn=+;
const int mod=1e9+; int n;
ll dp[maxn][]; void init()
{
dp[][]=;
dp[][]=;
for(int i=;i<=;i++)
{
for(int k=;k<;k++)
{
for(int j=;j<i;j++)
{
dp[i][k]=(dp[i][k]+dp[i--j][k-]*dp[j][k-])%mod;
dp[i][k]=(dp[i][k]+*dp[i--j][k-]*dp[j][k-])%mod;
}
}
}
} int main()
{
//freopen("in.txt","r",stdin);
init();
while(~scanf("%d",&n))
{
ll ans=;
for(int k=;k<;k++)
{
ans=(ans+dp[n][k])%mod;
}
printf("%lld\n",ans);
}
return ;
}