HDU 4359——Easy Tree DP?——————【dp+组合计数】

Easy Tree DP?

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1460    Accepted Submission(s): 557

Problem Description

A Bear tree is a binary tree with such properties : each node has a value of 20,21…2(N-1)(each number used only once),and for each node ,its left subtree’s elements’ sum<its right subtree’s elements’ sum(if the node hasn’t left/right subtree ,this limitation is invalid).
You need to calculate how many Bear trees with N nodes and exactly D deeps.

Input

First a integer T(T<=5000),then T lines follow ,every line has two positive integer N,D.(1<=D<=N<=360).

Output

For each test case, print "Case #t:" first, in which t is the number of the test case starting from 1 and the number of Bear tree.(mod 109+7)

Sample Input

2

2 2

4 3

Sample Output

Case #1: 4

Case #2: 72

Author

[email protected]_Brightroar

Source

2012 Multi-University Training Contest 6

题目大意:定义bear树是一棵二叉树。如果有左右子树,那么需要满足左子树的所有结点值总和小于右子树的所有结点值总和。每个结点的值都在20,21…2(N-1)中,这n个数只能被选一次。问你有多少种符合的方案。

解题思路:首先定义dp[i][j]表示有i个结点时,树深不超过j的方案数  。我们发现根结点是可以选任意值的。然后剩下的可以分情况考虑。首先考虑只有左子树或者右子树,那么剩下的i-1个结点就构成了只有左或右子树的情况,即dp[i-1][j-1]*2*i。然后考虑同时有左右子树的情况,我们在根结点放任意值,然后将i-1个值分到左右子树中,因为只要右子树中有一个剩下的i-1个值中的最大值那么就能满足要求。那么我们可以枚举k,让左子树从i-2个值中选k个,即i*C(i-2,k)*dp[k][j-1]*dp[i-1-k][j-1]。综上:可以得到dp转移方程:dp[i][j]=i*dp[i-1][j-1]*2+i*C(i-2,k)*dp[k][j-1]*dp[i-1-k][j-1]。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef __int64 INT;
const int MOD=1e9+7;
const int N=361;
INT C[400][400],dp[400][400];
//dp[i][j]表示有i个结点,树深不超过j的方案数
void getC(){    //得到组合数
    memset(C,0,sizeof(C));
    C[0][0]=1;
    for(int i=1;i<=N;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;
        }
    }
}
void getdp(){
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=N;i++)   //看做空树的情况
        dp[0][i]=1;
    for(int i=1;i<=N;i++)   //看做只有一个根结点的树的情况
        dp[1][i]=1;
    for(int i=2;i<=N;i++){
        for(int j=1;j<=N;j++){
            dp[i][j]=((2*C[i][i-1])%MOD*dp[i-1][j-1])%MOD;  //只有左或右子树的情况
            for(int k=1;k<=i-2;k++){
            //同时有左右子树的情况,根结点随意取,右子树中需要含有剩余的i-1个数中的最大值
                dp[i][j]+=((C[i][i-1]*C[i-2][k])%MOD*(dp[k][j-1]*dp[i-k-1][j-1]%MOD))%MOD;
                dp[i][j]%=MOD;
            }
        }
    }
}
int main(){
    getC();
    getdp();
    int t,n,d,cnt=0;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&d);
        //根据dp的定义,那么应将有n个结点,树深小于等于d-1的情况去掉才是树深为d的所有情况。题解说反复取模后dp[n][d]的值可能小于dp[n][d-1]。
        printf("Case #%d: %I64d\n",++cnt,((dp[n][d]-dp[n][d-1])%MOD+MOD)%MOD);
    }
    return 0;
}

  

时间: 2024-10-11 10:31:46

HDU 4359——Easy Tree DP?——————【dp+组合计数】的相关文章

HDU 4359 Easy Tree DP?(是dp但并不是tree dp + 组合计数)

HDU 4359 题意:定义Bear Tree为一颗二叉树,这种二叉树每个结点有一个权值,范围在2^0~2^n-1,并且每个值只用一次,对于每个结点,如果同时存在左右子树,那么左子树的权值和要小于右子树的权值和.求点数为N,层次为D的Bear Tree的数量. 思路: 2^0 + 2^1 + ... + 2^n < 2^(n+1) 根据这个性质,我们可以得出权值最大节点必须在右子树上,并且只要同时存在左右子树,则将权值最大节点放在右子树上就一定符合条件. 所以我们用dp[i][j]表示点数为i且

HDU 4359 Easy Tree DP?

Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1487    Accepted Submission(s): 567 Problem Description A Bear tree is a binary tree with such properties : each node has a value o

HDU 4359 Easy Tree DP? 带权二叉树的构造方法 dp

题意: 给定n deep 1.构造一个n个节点的带权树,且最大深度为deep,每个节点最多只能有2个儿子 2.每个节点的值为2^0, 2^1 ··· 2^(n-1)  任意两个节点值不能相同 3.对于一个节点,若他有左右儿子,则左子树的和 < 右子树的和 问: 有多少种构造方法. 思路: dp #include <stdio.h> #include <iostream> #include <algorithm> #include <cstring> u

HDU 4359 Easy Tree DP? 组合数学+动归

题意:定义一种树,每个节点的权值都是20到2n-1,每个权值出现一次,每个节点的左子树的权值和小于右子树.给你n和d,问有n个节点且恰好深度是d的这种树有多少种. 比赛的时候我没有做出来,当时A的人还是不少,\ 有一个超傻逼的居然没想到,就是  ,这表示一个权值较大的节点是大于所有权值小于他的值之和的. 所以对于每一个合法的树,只要把权值最大的放到右子树就可以满足了. 动归过程:f[i][j]表示i个节点深度不超过j的方案种数.

hdu 6035 Colorful Tree(树形dp+技巧)

题目链接:hdu 6035 Colorful Tree 题意: 给你一棵树,每个节点有一种颜色,现在让你求所有点对的路径上不同的颜色数量的总和. 题解: 下面是官方题解: 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可.直接做可以采用虚树的思想(不用真正建出来),对每种颜色的点按照 dfs 序列排个序,就能求出这些点把原来的树划分成的块的大小.这个过程实际上可以直接一次 dfs 求出. 这里的所说的单独考虑每种颜色,指的

hdu 5379 Mahjong tree 树形DP入门

Description Little sun is an artist. Today he is playing mahjong alone. He suddenly feels that the tree in the yard doesn't look good. So he wants to decorate the tree.(The tree has n vertexs, indexed from 1 to n.) Thought for a long time, finally he

hdu 5379 Mahjong tree 树形dp

链接 题意:给定一棵树 把1-n填到树的节点上,使得: 1:儿子节点上填的数字是连续的. 2:子树节点上填的数字是连续的. 把儿子节点分成两种,一种是叶子节点,一种是非叶子节点. 显然非叶子节点个数不能超过2个,不然就不存在这样的方案了. 然后分类讨论一下非叶子节点个数即可. #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdio> #i

HDU 4390 Number Sequence (容斥原理+组合计数)

HDU 4390 题意: 大概就是这样.不翻译了: Given a number sequence b1,b2-bn. Please count how many number sequences a1,a2,...,ansatisfy the condition thata1?a2?...?an=b1?b2?-?bn(ai,bi>1). 思路: 我们能够确定一件事:等号两边由同样数量的质因子组成. 假设ai能够等于1,答案就是把这些质因子分配进n个位置的方案数. 设左边的数字共由x个质因子组成

hdu 5379 Mahjong tree(树形dp)

题目链接:hdu 5379 Mahjong tree 树形dp,每个节点最多有2个子节点为一棵节点数大于1的子树的根节点,而且要么后代的节点值都大于,要么都小于本身(所以tson不为0是,要乘2).对于K个单一节点的子节点,种类数即为全排K!.当一个节点没有兄弟节点时,以这个节点为根结点的子树,根可以选择最大或者最小. #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu