标签:dp
题意:
给定n deep
1、构造一个n个节点的带权树,且最大深度为deep,每个节点最多只能有2个儿子
2、每个节点的值为2^0, 2^1 ··· 2^(n-1) 任意两个节点值不能相同
3、对于一个节点,若他有左右儿子,则左子树的和 < 右子树的和,不然不限制。
思路:设dp[ i ] [ j ]为结点数为i,深度不超过 j 的满足条件的树的个数。首先考虑invlid情况,即:
dp[ i ] [ j ] += 2×C[i] [i-1]×dp[ i - 1] [ j -1]。乘2是因为要么左子树为空要么右子树为空。 其次考虑valid情况,因为结点的权值很有特
点,只要最大权值的点在右子树就满足条件。那么枚举左子树的结点个数,不妨设为k,1<=k<=i-2,则右子树结点个数为i-1-k,那么:
dp[i][j]+=C[i][i-1]×dp[k][j-1]×dp[i-k-1]×C[i-2][k](最大点权已被选出)。初始化dp[1][...]为1,对于查询的n,m来说ans=dp[n][m]-dp[n][m-1]即
可,详见代码:
// file name: hdu4359.cpp // // author: kereo // // create time: 2015年1月26日 星期二 15时04分04秒 // //***********************************// #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int MAXN=300+100; const double eps=1e-8; const int inf=0x3fffffff; const int mod=1000000000+7; #define L(x) (x<<1) #define R(x) (x<<1|1) int n,m; ll dp[MAXN][MAXN],c[MAXN][MAXN]; void init(){ c[0][0]=1; memset(dp,0,sizeof(dp)); for(int i=1;i<MAXN;i++){ c[i][0]=c[i][i]=1; for(int j=1;j<i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } int main() { int T,kase=0; init(); for(int i=1;i<MAXN;i++) dp[1][i]=1; for(int i=2;i<MAXN;i++){ for(int j=1;j<MAXN;j++){ dp[i][j]=((c[i][i-1]*2)*dp[i-1][j-1])%mod; for(int k=1;k<=i-2;k++) dp[i][j]=(dp[i][j]+((dp[k][j-1]*c[i-2][k])%mod)*((dp[i-1-k][j-1]*c[i][i-1])%mod))%mod; } } scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); printf("Case #%d: %d\n",++kase,(int)(dp[n][m]-dp[n][m-1]+mod)%mod); } return 0; }
标签:dp
原文地址:http://blog.csdn.net/u011645923/article/details/43153385