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>
using namespace std;
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
///////////////////////////////////
typedef long long ll;
const int N = 362;
const ll mod = 1000000000 + 7;

int d[N][N], p[N][N], c[N][N];
int main() {
	memset(d, 0, sizeof d);
	memset(p, 0, sizeof p);
	memset(c, 0, sizeof c);
	for (int i = 0; i < N; ++i) {
		c[i][0] = c[i][i] = 1;
		for (int j = 1; j < i; ++j)
			c[i][j] = (c[i - 1][j] + c[i-1][j-1]) % mod;
	}
	for (int i = 0; i < N; ++i)
		p[0][i] = 1;
	for (int i = 1; i < N; ++i)
		p[1][i] = 1;
	for (int i = 2; i < N; ++i)
		for (int j = 1; j < N; ++j) {
			p[i][j] += (ll)p[i-1][j-1] * 2 % mod;
			p[i][j] %= mod;
			if (i - 1 >= 2) {
				for (int k = 1; k <= i - 2; ++k) {
					p[i][j] += ((ll)c[i-2][k] * p[k][j-1] % mod) * p[i-1-k][j-1] % mod;
					p[i][j] %= mod;
				}
			}
			p[i][j] = (ll)p[i][j] * i % mod;
		}
	//int x, y; while (~scanf("%d%d", &x, &y)) printf("%d\n", p[x][y]);
	d[1][1] = 1; d[0][0] = 1;
	for (int i = 2; i < N; ++i)
		for (int j = i; j < N; ++j) {
			d[i][j] += (ll)2 * d[i-1][j-1] % mod;
			d[i][j] %= mod;
			if (j - 1 >= 2) {
				for (int k = 1; k <= j - 2; ++k) {
					d[i][j] += ((ll)c[j-2][k] * p[k][i-2] % mod) * d[i-1][j-1-k] % mod;
					d[i][j] %= mod;
					d[i][j] += ((ll)c[j-2][k] * d[i-1][k] % mod) * p[j-1-k][i-2] % mod;
					d[i][j] %= mod;
					d[i][j] += ((ll)c[j-2][k] * d[i-1][k] % mod) * d[i-1][j-1-k] % mod;
					d[i][j] %= mod;
				}
			}
			d[i][j] = (ll)d[i][j] * j % mod;
		}
	int T = 0, cas, u, v;
	scanf("%d", &cas);
	while (cas -- > 0) {
		rd(u); rd(v);
		printf("Case #");
		pt(++T);
		putchar(':');
		putchar(' ');
		pt(d[v][u]);
		putchar('\n');
	}
	return 0;
}
时间: 2024-08-10 09:18:54

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?——————【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 o

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? 组合数学+动归

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

POJ1417:True Liars(DP+带权并查集)

True Liars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16338    Accepted Submission(s): 5724 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3038 Description: After having drifted about in a

hdu 3074 Zjnu Stadium (带权并查集)

Zjnu Stadium Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1744    Accepted Submission(s): 660 Problem Description In 12th Zhejiang College Students Games 2007, there was a new stadium built i

Codeforces.739E.Gosha is hunting(DP 带权二分)

题目链接 \(Description\) 有n只精灵,两种精灵球,每种球能捕捉到第i只精灵的概率已知.求用A个低级球和B个高级球能捕捉到精灵数的最大期望. \(Solution\) 设f[i][a][b]表示前i只用了a个低级球,b个高级球的最大期望.转移时四种情况显然.复杂度\(\mathcal O(nAB)\). 随着某种球可使用数的增多,f应是凸函数,即增长越来越慢.而且两种球都满足这个性质. 于是可以wqs二分套wqs二分了..没有个数限制取个max记一下个数就可以了.复杂度\(\mat

HDU 2818 Building Block(带权并查集)

[题目链接]:Click here~~ [题意]: 给 n 块砖头,开始各为一堆,两种操作: 1.把 X 所在的那一堆箱子里的砖头放到 Y 所在的那一堆上面. 2.询问 X 下面有多少块砖. [解题思路]:好像大家都叫它带权并查集,那为了方便,这里也这样叫吧,因为涉及前面的和后面的箱子个数,对应的查找操作,一开始想用结构体来写,在结构体里定义每个箱子的前驱和后继,每次输入的时候统计一下相应的前驱和后继的个数,后来发现不行,因为涉及到合并操作,比如说M 2 4 M 2 6连续出现两个2,用结构体是

HDU(1856),裸的带权并查集

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1856 题意:朋友圈问题,A和B是朋友,B和C是朋友则A和C也是朋友,依次类推,题目的意思就是求最大的朋友圈,即求最大集合中元素的个数.裸的并查集加个秩数组就行了. #include <stdio.h> int father[100050]; int rank[100050]; int Find_Set (int x) { if(x!=father[x]) father[x] = Find_Set(