1. 程式人生 > >HDU 4359 Easy tree DP? -- 我只能說是個dp

HDU 4359 Easy tree DP? -- 我只能說是個dp

/*
	HDU 4359 Easy tree DP?
	題意:求任意節點下左子樹最大值小於右子樹最大值的二叉樹方案數
	
	我只能說這是一個dp(rt)

	狀態:i個節點在滿足不大於j深度有 dp[i][j] 種方案數
	初始化:
	        CLR(dp,0)
	        dp[1][1~360] = 1  各種深度僅一個節點方案數為1
	轉移:
	(1)i箇中挑一個為root 並且該root僅有左子樹(or右子樹,so ×2)
		dp[i][j] += dp[i-1][j-1]*nCr(i,i-1)*2 
	(2)i箇中挑一個為root 並且該root有左子樹(假設擁有k個節點)and右子樹
		dp[i][j] += 
		nCr(i-2,k) *	    從i-2(因為去掉了一個root和一個必須放在右子樹的最大節點)箇中挑k個的方案數
		dp[k][j-1] *	    從i-2箇中挑出的k個作為root的左子樹的方案數   (因為沒算root那一層所以j-1)
		dp[i-1-k][j-1] *    上面挑剩下的i-1-k個節點構成{深度<=j-1}的方案數 (因為沒算root那一層所以j-1)
		nCr(i,i-1)	    從i箇中挑1個為root的方案數

*/

#pragma comment(linker, "/STACK:102400000,102400000")
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <vector>
#include <ctime>
#include <queue>
#include <cmath>
#include <set>
#define CLR(a,v) memset(a,v,sizeof(a))
using namespace std;
typedef long long       ll;
typedef pair<int,int>   pii;

const int N   = 360 + 10;
const ll  MOD = 1e9 + 7;
int n,d;
ll C[N][N]={0};
ll dp[N][N]={0}; // i個節點在滿足不大於j深度有 dp[i][j] 種方案數

ll nCr(ll n,ll r){
	if(C[n][r]!=-1)return C[n][r];
	if(n==r)return 1;
	if(n<r)return 0;
	if(r==1)return n;
	return C[n][r] = (nCr(n-1,r-1) + nCr(n-1,r))%MOD;
}

void pre(){
	CLR(C,-1);
	int n_p = 360;
	int depth = 360;
	// 初始化各種深度,0個點方案數為1,1個點方案數也為1
	for(int j = 1 ; j <= depth ; j++)
		dp[1][j] = 1;

	for(int i = 2 ; i <= n_p ; i++){
		for(int j = 1 ; j <= depth ; j++){
			dp[i][j] = nCr(i,1)*dp[i-1][j-1]%MOD *2%MOD;
			if(dp[i][j] >= MOD)	dp[i][j] %= MOD;
			for(int k = 1 ; k <= i-2 ; k++){ 
				// 雖然選取一個做為root,但是剩餘中最大的應該在最右葉子上,因此去掉兩個點
				// 保證root左子樹不為空,因此 k >= 1
				// k表示 root左子樹上有k個點
				//            左k個點   右i-1-k個點        左挑k個        root的挑法
				dp[i][j] += dp[k][j-1] * dp[i-1-k][j-1]%MOD * nCr(i-2,k)%MOD * nCr(i,1) % MOD;
				if(dp[i][j] >= MOD)	dp[i][j] %= MOD;
			}
		}
	}
}

int main(){
	//freopen("in.txt","r",stdin);
	//freopen("Output.txt","w",stdout);
	pre();
	int T,ca=0;cin >> T;
	while(T--){
		scanf("%d%d",&n,&d);
		printf("Case #%d: %I64d\n",++ca, (dp[n][d] - dp[n][d-1] + MOD)%MOD);
	}
	return 0;
}