spoj8549 BST again dp

题意:给你n和h,问有多少棵n个节点高度为h的二叉搜索树(标号为1-n,只有一个节点的树高为0),答案对10^9+7取模。

思路:设dp[ n ][ h ]为 n 个节点高度不超过 h 的二叉搜索树的个数。那么dpn,h=∑i=0n-1dpi,h?1?dpn?i-1,h?1

即选定一个点,枚举左子树的个数问为 i ,剩余右子树的个数即为n - 1 - i 。详见代码:

/*********************************************************
  file name: spoj8549.cpp
  author : kereo
  create time:  2014年12月05日 星期五 22时45分10秒
*********************************************************/
#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 N=500+50;
const int MAXN=100000+50;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
int n,m;
ll dp[N][N];
ll dfs(int n,int m){
	if(m<0)
		return 0;
	if(dp[n][m]!=-1)
		return dp[n][m];
	dp[n][m]=0;
	if(n == 0){
		dp[n][m]=1;
		return dp[n][m];
	}
	for(int i=0;i<=n-1;i++){
		dp[n][m]+=dfs(i,m-1)*dfs(n-1-i,m-1);
		if(dp[n][m]>=mod)
			dp[n][m]%=mod;
	}
	return dp[n][m];
}
int main(){
	int T;
	scanf("%d",&T);
	memset(dp,-1,sizeof(dp));
	while(T--){
		scanf("%d%d",&n,&m); m++;
		printf("%lld\n",(dfs(n,m)-dfs(n,m-1)+mod)%mod);
	}
	return 0;
}
时间: 2024-11-02 18:21:30

spoj8549 BST again dp的相关文章

【BZOJ3769】spoj 8549 BST again DP(记忆化搜索?)

[BZOJ3769]spoj 8549 BST again Description 求有多少棵大小为n的深度为h的二叉树.(树根深度为0:左右子树有别:答案对1000000007取模) Input 第一行一个整数T,表示数据组数. 以下T行,每行2个整数n和h. Output 共T行,每行一个整数表示答案(对1000000007取模) Sample Input 2 2 1 3 2 Sample Output 2 4 HINT 对于100%的数据,1<=n<=600,0<=h<=60

codeforce #505D - Recovering BST 区间DP

1025D 题意: 有一个递增序列,问能不能构建出一颗每条边的端点值都不互质的二叉排序树. 思路: 区间DP,但是和常见的区间DP不一样, 这里dp[i][j]表示的是区间[i,j]能否以i为根建立一个小二叉排序树. 所以可以得到dp[i][j] 为true, 要求在[i+1,j]中有一个k,dp[k][i+1]和dp[k][j]都为true. 或者在i点的左边取件中,即要求在[j][i-1]中有一个k,dp[k][j]和dp[k][i-1]都为true. #include <algorithm

BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )

WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就是记忆化搜一下...重边就用set判一下 ------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring

uva 10304 - Optimal Binary Search Tree 区间dp

题目链接 给n个数, 这n个数的值是从小到大的, 给出个n个数的出现次数. 然后用他们组成一个bst.访问每一个数的代价是这个点的深度*这个点访问的次数. 问你代价最小值是多少. 区间dp的时候, 如果l >= r, 那么返回0, l == r-1, 返回两个数中小的一个. 其他情况的话枚举分界点进行状态转移. #include <bits/stdc++.h> using namespace std; #define mem1(a) memset(a, -1, sizeof(a)) co

面试题22:有序数组生成BST

对于一个含有n个数的有序数组1~N,能够产生多少种不同结果的二叉搜素树BST? 如何生成这些不同结构的BST? 1 class Solution { 2 public: 3 int numTrees(int n) { 4 int* dp = new int[n+1]; 5 dp[0] = 1; 6 dp[1] = 1; 7 dp[2] = 2; 8 for(int i=3;i<=n;i++){ 9 dp[i] = 0; 10 for(int j=1;j<=i;j++){ 11 dp[i]+=d

UVA10304---(区间DP)

第一开始想着枚举根节点,然后记忆化搜索..结果TLE,最后还是看了一眼题解瞬间明白了..唉,还是思维太局限了 由于数据是按照从小到大排列的,可以自然地组成一颗二叉排序树. 设dp[i][j]是区间[i,j]的元素可以组成的BST的最小值,则大区间的结果和根节点以及小区间的结果有关系,很明显区间DP, 转移方程搭dp[i][j] = min{dp[i][k-1] + dp[k+1][j] + sum(i,j) - a[k]} sum(i,j)是区间和,因为当把两棵左右子树连在 根节点上时,本身的高

Unique Binary Search Trees(dp)

Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For example,Given n = 3, there are a total of 5 unique BST's. 1 3 3 2 1 \ / / / \ 3 2 1 1 3 2 / / \ 2 1 2 3 BST树的定义:根节点左边所有节点的值小于根节点值,右边所有节点的值大于根节点的值,然后其左右子树又是

POJ 3017 Cut the Sequence (单调队列优化DP)

POJ 3017 Cut the Sequence (单调队列优化DP) ACM 题目地址: POJ 3017 Cut the Sequence 题意: 将一个由N个数组成的序列划分成若干段,要求每段数字的和不超过M,求[每段的最大值]的和 的最小的划分方法,输出这个最小的和. 分析: 方程是:dp[i] = min(dp[j]+maxsum[j+1][i]) 但复杂度n*n太高,需要优化. 可以用单调队列+BST优化,其实只需要维护每一段的最大值. 看了这篇题解的:http://blog.cs

Leet Code -- Unique BST

对于数字n(大于1),从1到n有多少种binary search tree(BST序列)?当n=3时,BST序列为: 1         3     3    2     1     \         /     /      / \      \     3      2    1    1  3     2     /       /       \                  \   2      1         2                3共5种. 分析: N=1时,