『题解』 Codeforces9Dどのように多くの木?

より良い読書体験

ポータル

Portal1:Codeforces

Portal2:Luogu

説明

1つの非常に古いテキストファイルに書かれた偉大な知恵がありました。メインフレームの住民の中で最も古い - この知恵は誰も、さえフォンを、それを解読することができなかったことをとても素晴らしかったです。しかし、まだ彼はそこからいくつかの情報を得ることができました。例えば、彼はそのユーザーが喜びのためにゲームを起動学ぶことができた - その後、ひどいゲームキューブは、ゲームに勝つことができないこれらのモジュールに死をもたらし、都市に落ちます...

ガードボブはメインフレームに現れたとして確かに、多くのモジュールは、ゲームキューブを恐れ停止しました。ボブは(彼はまだ生きていると)、ユーザーによって敗北されていない、と彼はこれにプログラムされているので、彼は常に、ゲームキューブでmeddlesので。

しかし、不快な状況がゲームキューブが失われた角度に倒れたときに、発生する可能性があります。進、...うーん...非常に奇妙である - 厄介なウイルスがそこに住んでいるので。そして、彼女は非常に遊ぶのが好き。だから、行き当たりばったり、ボブは、ユーザと、その後の彼女の最初と遊ぶ、としています。

この時間は、16進、以下のエンターテインメントを発明:ボブは、n個のノードを持つ二分探索木の上に跳躍する必要があります。、ノードの左側のサブツリーは、ノードのキーより小さいキーを持つノードのみが含まれている権利を:私たちは、次が真である各ノードについて、各ノードが別々の鍵を持って、二分探索木がバイナリツリーであることを思い出させる必要がありますノードのサブツリーは、ノードのキーより大きいキーを持つノードのみが含まれています。すべてのキーは異なる正の整数である\(1 \)する\(N \) このようなツリーの各ノードは最大2人の子供がいる、または全く子供を持つことはできません(場合には、ノードが葉である場合)。

進数のゲームでは、すべての木は異なりますが、それぞれの高さがh以上です。この問題«高さは»遠いルートからリーフまでの途中のノードの最大量を意味では、ルートノードと葉自体は含まれています。ボブは木の上に飛躍すると、それが消えます。ボブは、残された樹木がない場合、キューブへのアクセス権を取得します。彼は、最悪の場合にはオーバー飛躍する必要がありますどのように多くの木を知っています。あなたも?

入力

入力データは、2つのスペースで区切られた正の整数が含まれている(N \)\\(H(Nル35、H \ルを\ n)\)

出力

出力1つの番号-問題への答え。超えていないことが保証されている\(9 \回10 ^ 18 \を)

サンプル入力1

3 2

サンプル出力1

5

サンプル入力2

3 3

サンプル出力2

4

中国での説明

\(N \)二分木からなる点、以上の高さを尋ねる\(時間\)が何です。

溶液

この問題\(N \)範囲のみ、非常に小さい(35 \)\ので、我々は使用\(O(N ^ 4) \) 解決するために、動的プログラミングを。

dp[i][j]で表される\(Iは\)ポイント、高さを構成する\(J \)は二分木の数です。

動的転送方程式\(DP [I] [MAX(J、K)+ 1] + = DP [L] [J] \タイムズDP [R&LT] [K] \) \は(私は\)使用表さノードの数、\(J \)は、ノードの左サブツリーを列挙し、\(Lの\)はサブツリーを左ノード点の総数を表し、\(K \)は、ノードの左サブツリーを列挙\(R&LTを\)右サブツリーにおけるノードの総数を表します。

答えは(\ {N-SUM ^を} = H _ {I} {DP [N-] [I]} \)\します

コード

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>

using namespace std;

typedef long long LL;
const int MAXN = 40;
int n, h;
LL dp[MAXN][MAXN];
int main() {
    scanf("%d%d", &n, &h);
    dp[0][0] = 1;//用0个结点,可以构造出1棵深度为0的二叉树
    for (int i = 1; i <= n; i++)//枚举总结点数
        for (int L = 0; L < i; L++) {//枚举左子树的结点数
            int R = i - L - 1;//计算剩下的结点数,再减去根结点,就是右子树的结点数
            for (int j = 0; j <= L; j++)//左子树
                for (int k = 0; k <= R; k++)//右子树
                    dp[i][max(j, k) + 1] += dp[L][j] * dp[R][k];//因为是累计可行方案所以是乘法
        }
    LL ans = 0;
    for (int i = h; i <= n; i++)
        ans += dp[n][i];//累计答案
    printf("%lld\n", ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/shenxiaohuang/p/11317996.html