Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Ignore the actual key values for a second. In a BST on keys , if the root is , then the left subtree must use exactly keys and the right subtree exactly . So the count really depends on subtree sizes.
The condition is height at least . Counting that directly is kind of a pain. Try the complement: count BSTs with height at most , then subtract from the total.
A useful state is = number of BSTs with nodes and height at most . To make the recurrence not suck, let the empty tree count as one tree: . Also, for every .
If the left subtree has nodes, then the right subtree has . For the whole tree to have height at most , both subtrees must have height at most . That should give you a sum over all .
The recurrence is
Compute this bottom-up for . Since any BST with nodes has height at most , the total number of BSTs is . Therefore the answer is
First, strip away the cyber-fairy-tale nonsense. We need the number of BSTs on keys whose height is at least .
For a BST with keys , once the root key is fixed to some :
So the number of possibilities depends only on the sizes of the two subtrees.
If the left subtree has nodes, then the right subtree has nodes. That is the only split information that matters.
So this is a DP on subtree sizes, not on actual key values.
Trying to count trees with height at least directly is annoying as hell. The standard trick is cleaner:
Define
Then the answer is
Since height is an integer, that becomes
Why is the total number of BSTs? Because any tree with nodes has height at most ; the worst case is just a chain.
We treat the empty tree as a valid helper object of height . This makes the recurrence nice instead of cursed.
A non-empty tree cannot have height . Pretty revolutionary stuff.
Take a BST with nodes and height at most .
Suppose the left subtree has nodes. Then:
So the number of possibilities for this split is
Summing over every possible split:
And that's the whole trick.
No extra combinatorial factor is needed. Once the left subtree size is :
Each pair of left/right BSTs gives exactly one BST of size .
The recurrence is a bijection, which is the kind of thing DP likes and humans tolerate.
For every BST counted by :
So every valid tree contributes to exactly one term in the sum.
Conversely, if you take:
and attach them as left/right children of the forced root, you get a unique BST with nodes and height at most .
So the recurrence counts exactly the right objects.
There are states, and each state tries all possible left-subtree sizes.
Therefore the time complexity is
Since , this is tiny. You can brute-force your DP table and still have time left to laugh at the story.
Memory usage is
dp[n][k] for all .This is basically Catalan DP with a height cap. Same family, slightly more attitude.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int n, h;
cin >> n >> h;
vector<vector<ll>> dp(n + 1, vector<ll>(n + 1, 0));
// Empty tree: one way, and its height is 0, so it is valid for any limit k >= 0.
for (int k = 0; k <= n; ++k) dp[0][k] = 1;
// dp[nodes][k] = number of BSTs with 'nodes' nodes and height at most k.
for (int k = 1; k <= n; ++k) {
for (int nodes = 1; nodes <= n; ++nodes) {
ll cur = 0;
for (int left = 0; left <= nodes - 1; ++left) {
int right = nodes - 1 - left;
cur += dp[left][k - 1] * dp[right][k - 1];
}
dp[nodes][k] = cur;
}
}
ll total = dp[n][n]; // every n-node BST has height at most n
ll shortEnough = dp[n][h - 1]; // trees with height < h
cout << total - shortEnough << '\n';
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int n, h;
cin >> n >> h;
vector<vector<ll>> dp(n + 1, vector<ll>(n + 1, 0));
// Empty tree: one way, and its height is 0, so it is valid for any limit k >= 0.
for (int k = 0; k <= n; ++k) dp[0][k] = 1;
// dp[nodes][k] = number of BSTs with 'nodes' nodes and height at most k.
for (int k = 1; k <= n; ++k) {
for (int nodes = 1; nodes <= n; ++nodes) {
ll cur = 0;
for (int left = 0; left <= nodes - 1; ++left) {
int right = nodes - 1 - left;
cur += dp[left][k - 1] * dp[right][k - 1];
}
dp[nodes][k] = cur;
}
}
ll total = dp[n][n]; // every n-node BST has height at most n
ll shortEnough = dp[n][h - 1]; // trees with height < h
cout << total - shortEnough << '\n';
}