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且深度不超过j的所有方案数,那么输出结果就是dp[n][d]-dp[n][d-1]。

而dp[n][d]的构成分下面两种:

1是只有左子树或只有右子树的情况,我们发现,只需要取任意一个节点来做根节点,乘以可能的子树情况(即dp[n-1][d-1]),再区别开是左子树还是右子树,总共有dp[n-1][d-1] * C(n,1) * 2种情况。

2是同时有左右子树的情况,我们假设左子树有k个节点,则有dp[n-k-1][d-1]【右子树】 * dp[k][d-1]【左子树】 * C(n-2,k) 【左子树节点组成】* C(n,1)【根节点选择】

我们把一二相加即可得到转移方程,值得注意的是,由于n ,k<= 360随时可能爆精度,每次操作都尽可能模除10^9+7.

Code:

/*
* @author Novicer
* language : C++/C
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
#define INF 2147483647
#define cls(x) memset(x,0,sizeof(x))
#define rise(i,a,b) for(int i = a ; i <= b ; i++)
using namespace std;
const double eps(1e-8);
typedef long long lint;

const int maxn = 365;
const int maxd = 365;
const lint mod = 1e9 + 7;
lint dp[maxn][maxd];
lint C[maxn][maxd];
void init(){
	cls(C);
	memset(dp,-1,sizeof(dp));
	C[0][0] = 1;
	for(int i = 1 ; i < maxn  ; i++){
		C[i][0] = 1;
		for(int j = 1 ; j <= i ; j++){
			C[i][j] = C[i-1][j-1] + C[i-1][j];
//			printf("C[%d][%d] : %I64d\n" ,i ,j ,C[i][j]);
			if(C[i][j] > mod) C[i][j] -= mod;
		}
	}
}

lint f(int n , int d){
	if(n == 1 && d >= 1) return 1;
	if(n == 1 || d == 0) return 0;
	if(dp[n][d] != -1) return dp[n][d];
	lint &ans = dp[n][d];
	ans = (f(n-1 , d-1) * C[n][1] * 2) % mod;
	for(int k = 1 ; k <= n-2 ; k++)
		ans = (ans + ((( ( (f(n-k-1 , d-1) * f(k , d-1)) % mod) * C[n-2][k]) % mod) * C[n][1]) % mod) % mod;
	return ans;
}

int main(){
	int t ; cin >> t ; int kase = 1;
	init();
	while(t--){
		int n , d;
		cin >> n >> d;
		lint ans = f(n,d) - f(n,d-1);
		ans = (ans + mod) % mod;
		cout << "Case #" << kase++ << ": " << ans << endl;
	}
	return 0;
}

版权声明:博主表示授权一切转载:)

时间: 2024-10-28 04:00:26

HDU 4359 Easy Tree DP?(是dp但并不是tree dp + 组合计数)的相关文章

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? 带权二叉树的构造方法 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 5378 Leader in Tree Land(2015 多校第7场 dp)

Leader in Tree Land Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 150    Accepted Submission(s): 54 Problem Description Tree land has  cities, connected by  roads. You can go to any city from

hdu 4081 Qin Shi Huang&#39;s National Road System(最小生成树+dp)

同样是看别人题解才明白的 题目大意—— 话说秦始皇统一六国之后,打算修路.他要用n-1条路,将n个城市连接起来,并且使这n-1条路的距离之和最短.最小生成树是不是?不对,还有呢.接着,一个自称徐福的游方道士突然出现,他说他可以不消耗任何人力财力,使用法术凭空造一条路,路的长度无所谓,但是只能造一条.那么问题来了,徐福希望将两座人口数最多的城市连接起来,而秦始皇希望将最长的路修好.最后折中了一下, 将A/B最大的一条路用法术修出来.其中A是两座城市的人口和,B是除了用法术修的路以外,其它需要修建的

2014 HDU多校弟九场I题 不会DP也能水出来的简单DP题

听了ZWK大大的思路,就立马1A了 思路是这样的: 算最小GPA的时候,首先每个科目分配到69分(不足的话直接输出GPA 2),然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到100即可 算最大GPA的时候,首先每个科目分配到60分,然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到85即可,如果还有REMAIN POINT,就FOR循环下来加到100上限即可 不会DP 阿 QAQ 过段时间得好好看DP了  =  = 于是默默的把这题标记为<水题集> //

HDU 1561 ——The more, The Better(有依赖的树形DP)

题目分析: 攻占城堡所能获得的最多宝物,但是有个限制,要想攻占某个城堡前必须先攻占另一个城堡 思路: 建图,新建一个根节点为0,那么题目就变为要想取得子节点必须先取得它的父亲节点 今天为了解决这个问题,看了下背包九讲中的有依赖的背包,刷了道模板题. 大概思路是:要想取得附件必须先取主件,主件要么取,要么不取,取得话要怎么分配给附件,用01背包处理附件,然后再把每个主件分组背包 树形的依赖主要是附件是个集合,附件还有附件.森林的概念 根据DP的思想,我们先dfs到叶,01背包操作 即可.只是每次d

HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp

随机输出保平安啊 和hdu4888一个意思,先跑个网络流然后dp判可行. ==n^3的dp过不了,所以把n改成200. ==因为出题人没有把多解的情况放在200*200以外的矩阵. #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int MAX_N = 12