In one very old text file there was written Great Wisdom. This Wisdom was so Great that nobody could decipher it, even Phong — the oldest among the inhabitants of Mainframe. But still he managed to get some information from there. For example, he managed to learn that User launches games for pleasure — and then terrible Game Cubes fall down on the city, bringing death to those modules, who cannot win the game...

For sure, as guard Bob appeared in Mainframe many modules stopped fearing Game Cubes. Because Bob (as he is alive yet) has never been defeated by User, and he always meddles with Game Cubes, because he is programmed to this.

However, unpleasant situations can happen, when a Game Cube falls down on Lost Angles. Because there lives a nasty virus — Hexadecimal, who is... mmm... very strange. And she likes to play very much. So, willy-nilly, Bob has to play with her first, and then with User.

This time Hexadecimal invented the following entertainment: Bob has to leap over binary search trees with n nodes. We should remind you that a binary search tree is a binary tree, each node has a distinct key, for each node the following is true: the left sub-tree of a node contains only nodes with keys less than the node's key, the right sub-tree of a node contains only nodes with keys greater than the node's key. All the keys are different positive integer numbers from 1 to n. Each node of such a tree can have up to two children, or have no children at all (in the case when a node is a leaf).

In Hexadecimal's game all the trees are different, but the height of each is not lower than h. In this problem «height» stands for the maximum amount of nodes on the way from the root to the remotest leaf, the root node and the leaf itself included. When Bob leaps over a tree, it disappears. Bob gets the access to a Cube, when there are no trees left. He knows how many trees he will have to leap over in the worst case. And you?

Input

The input data contains two space-separated positive integer numbers n and h (n ≤ 35, h ≤ n).

Output

Output one number — the answer to the problem. It is guaranteed that it does not exceed 9·1018.

Examples

Input

3 2


Output

5

Input

3 3


Output

4
#include <bits/stdc++.h>
using namespace std;
const long double PI = 2 * acos(0.0);
const int stdLength = 25;
const long long max_number = 1048575;
void print(vector<bool> &a) {
  for (bool i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<int> &a) {
  for (int i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<char> &a) {
  for (char i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<long long> &a) {
  for (long long i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<vector<int>> &a) {
  for (vector<int> i : a) {
    print(i);
  }
  cout << "\n";
}
void print(vector<vector<long long>> &a) {
  for (vector<long long> i : a) {
    print(i);
  }
  cout << "\n";
}
void print(vector<double> &a) {
  for (double i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<long double> &a) {
  for (long double i : a) {
    cout << i << " ";
  }
  cout << "\n";
}
void print(vector<pair<long long, long long>> &a) {
  for (auto i : a) {
    cout << "(" << i.first << ", " << i.second << ") ";
  }
  cout << "\n";
}
void print(vector<pair<int, int>> &a) {
  for (auto i : a) {
    cout << "(" << i.first << ", " << i.second << ") ";
  }
  cout << "\n";
}
void print(pair<int, int> &p) {
  cout << "(" << p.first << ", " << p.second << ") ";
}
void print(deque<pair<long long, long long>> &a) {
  for (pair<long long, long long> i : a) {
    cout << i.first << " " << i.second << "\n";
  }
  cout << "\n";
}
long long dist_sq(pair<long long, long long> a, pair<long long, long long> b) {
  return ((a.first - b.first) * (a.first - b.first) +
          (a.second - b.second) * (a.second - b.second));
}
long long po(long long a, long long b) {
  if (b <= 0)
    return 1;
  else if (b == 1)
    return a;
  long long vl = po((a * a), b / 2);
  if (b % 2 == 0)
    return vl;
  else
    return (vl)*a;
}
long long pomod(long long a, long long b) {
  a = a % 1000000007LL;
  if (b <= 0)
    return 1 % 1000000007LL;
  else if (b == 1)
    return a % 1000000007LL;
  long long vl = pomod((a * a) % 1000000007LL, b / 2);
  vl = vl % 1000000007LL;
  if (b % 2 == 0)
    return vl;
  else
    return ((vl)*a) % 1000000007LL;
}
long long pomod(long long a, long long b, long long mo) {
  a = a % mo;
  if (b <= 0)
    return 1 % mo;
  else if (b == 1)
    return a % mo;
  long long vl = pomod((a * a) % mo, b / 2);
  vl = vl % mo;
  if (b % 2 == 0)
    return vl;
  else
    return ((vl)*a) % mo;
}
long long factmod(long long n, long long mo) {
  long long val = n;
  long long ans = 1;
  while (val >= 1) {
    ans = (ans * val) % mo;
    val--;
  }
  return ans;
}
long long inv(long long a, long long mo) { return pomod(a, mo - 2, mo); }
long long combinationMod(long long n, long long i) {
  long long ans = 1;
  ans = (ans * factmod(n, 1000000007LL)) % 1000000007LL;
  long long invVal =
      (inv(factmod(i, 1000000007LL), 1000000007LL) % 1000000007LL *
       inv(factmod(n - i, 1000000007LL), 1000000007LL) % 1000000007LL) %
      1000000007LL;
  ans = (ans * invVal) % 1000000007LL;
  return ans;
}
long long greatestCommonDivisor(long long a, long long b) {
  if (b > a) {
    return greatestCommonDivisor(b, a);
  }
  if (b == 0) {
    return a;
  }
  if (a % b == 0) {
    return b;
  } else {
    return greatestCommonDivisor(b, a % b);
  }
}
long long greatestCommonDivisor(const vector<long long> &numList, int st,
                                int en) {
  assert(st >= 0 and st < (int)numList.size());
  assert(en >= 0 and en < (int)numList.size());
  if (st > en) {
    return 0;
  } else if (st == en) {
    return numList[st];
  } else if (en == st + 1) {
    return greatestCommonDivisor(numList[st], numList[st + 1]);
  } else {
    return greatestCommonDivisor(numList[st],
                                 greatestCommonDivisor(numList, st + 1, en));
  }
}
long long greatestCommonDivisor(const vector<long long> &numList) {
  if (numList.size() == 0) {
    return 0;
  }
  int st = 0;
  int en = numList.size();
  en--;
  return greatestCommonDivisor(numList, st, en);
}
vector<vector<long long>> preComputeCombinationMod(int n) {
  vector<vector<long long>> comb(n + 1, vector<long long>(n + 1, 0));
  comb[0][0] = 1;
  for (long long i = (1); i <= (n); i++) {
    comb[i][0] = 1;
    comb[0][i] = 0;
  }
  for (long long i = (1); i <= (n); i++) {
    for (long long j = (1); j <= (i); j++) {
      comb[i][j] =
          (comb[i - 1][j - 1] % 1000000007LL + comb[i - 1][j] % 1000000007LL) %
          1000000007LL;
    }
  }
  return comb;
}
long long floorlog2(long long n) {
  long long h = 0;
  long long p = 1;
  while (p <= n) {
    h++;
    p *= 2;
  }
  return h - 1;
}
long long floorlog2(long long n, long long b) {
  long long h = 0;
  long long p = 1;
  while (p <= n) {
    h++;
    p *= b;
  }
  return h - 1;
}
class Trie {
 private:
  vector<Trie *> children;
  bool this_inserted = false;

 public:
  Trie() {
    children.resize(26, NULL);
    this_inserted = false;
  }
  void insert(string word) {
    Trie *cur = this;
    for (char c : word) {
      int ind = c - 'a';
      if (cur->children[ind] == NULL) {
        cur->children[ind] = new Trie();
      }
      cur = cur->children[ind];
    }
    cur->this_inserted = true;
  }
  bool search(string word) {
    Trie *cur = this;
    for (char c : word) {
      int ind = c - 'a';
      if (cur->children[ind] == NULL) {
        return false;
      }
      cur = cur->children[ind];
    }
    return cur->this_inserted;
  }
  bool startsWith(string prefix) {
    string word = prefix;
    Trie *cur = this;
    for (char c : word) {
      int ind = c - 'a';
      if (cur->children[ind] == NULL) {
        return false;
      }
      cur = cur->children[ind];
    }
    return true;
  }
};
class FenwickTree {
 public:
  vector<long long> BIT;
  FenwickTree(int n = 100000) { BIT.resize(n + 1, 0); }
  FenwickTree(vector<long long> a) {
    int n = a.size();
    BIT.resize(n + 1, 0);
    for (long long i = (0); i <= (n - 1); i++) {
      update(i + 1, a[i]);
    }
  }
  FenwickTree(vector<int> a) {
    vector<long long> b(a.begin(), a.end());
    int n = b.size();
    BIT.resize(n + 1, 0);
    for (long long i = (0); i <= (n - 1); i++) {
      update(i + 1, b[i]);
    }
  }
  void update(int ind, long long val) {
    assert(0 <= ind and ind < BIT.size());
    int first = ind;
    int sz = BIT.size();
    while (first < sz) {
      BIT[first] += val;
      first += (first & -first);
    }
  }
  void set(int ind, long long val) {
    assert(0 <= ind and ind < BIT.size());
    long long currentVal = query(ind, ind);
    update(ind, val - currentVal);
  }
  long long query(int l, int r) {
    assert(0 <= l and r < BIT.size());
    if (r < l) {
      return 0;
    } else
      return prefQuery(r) - prefQuery(l - 1);
  }
  long long prefQuery(int ind) {
    assert(0 <= ind and ind < BIT.size());
    int first = ind;
    long long sum = 0;
    while (first > 0) {
      sum += BIT[first];
      first -= (first & -first);
    }
    return sum;
  }
};
class FenwickTreeRangeUpdate {
 public:
  FenwickTree bitTree;
  FenwickTreeRangeUpdate(int n) { bitTree = FenwickTree(n + 1); }
  void updateRange(pair<int, int> indexRange, long long val) {
    bitTree.update(indexRange.first, val);
    bitTree.update(indexRange.second + 1, -val);
  }
  long long query(int ind) { return bitTree.prefQuery(ind); }
};
struct P {
  int data, version;
  P(int d = 0, int ver = 0) : data(d), version(ver) {}
  inline friend bool operator<(const P &a, const P &b) {
    return a.version < b.version;
  }
};
class PersistentFenwickTree {
 public:
  vector<vector<P>> BIT;
  int currentVersion;
  PersistentFenwickTree(int n = 100000) {
    BIT.resize(n + 1, {P()});
    currentVersion = 0;
  }
  void update(int ind, long long val) {
    assert(0 <= ind and ind < BIT.size());
    int first = ind;
    int sz = BIT.size();
    currentVersion += 1;
    while (first < sz) {
      if (BIT[first].empty()) {
        throw logic_error("empty array spot");
      }
      auto newVal = P(BIT[first].back().data + val, currentVersion);
      BIT[first].push_back(newVal);
      first += (first & -first);
    }
  }
  long long prefQuery(int ind, int version) {
    assert(0 <= ind and ind < BIT.size());
    int first = ind;
    long long sum = 0;
    while (first > 0) {
      if (BIT[first].empty()) {
        throw logic_error("empty array spot");
      }
      auto node = *(
          upper_bound(BIT[first].begin(), BIT[first].end(), P(0, version)) - 1);
      sum += node.data;
      first -= (first & -first);
    }
    return sum;
  }
};
class PersistentFenwickTreeRangeUpdate {
 public:
  PersistentFenwickTree bitTree;
  PersistentFenwickTreeRangeUpdate(int n) {
    bitTree = PersistentFenwickTree(n + 1);
  }
  void updateRange(pair<int, int> indexRange, long long val) {
    bitTree.update(indexRange.first, val);
    bitTree.update(indexRange.second + 1, -val);
  }
  long long query(int ind, int version) {
    return bitTree.prefQuery(ind, version);
  }
};
vector<long long> getPrimes(long long highestNum) {
  vector<bool> isPrime(highestNum + 5, true);
  vector<long long> primes;
  for (long long i = (2); i <= (highestNum); i++) {
    if (isPrime[i]) {
      primes.push_back(i);
      long long j = i;
      while (j * i <= highestNum) {
        isPrime[j * i] = false;
        j++;
      }
    }
  }
  return primes;
}
long long getMultiplicity(long long num, long long prime) {
  long long mult = 0;
  while (num % prime == 0) {
    mult += 1;
    num /= prime;
  }
  return mult;
}
vector<long long> getPrimeFactorization(long long num,
                                        vector<long long> &primes) {
  int sz = primes.size();
  vector<long long> multcities(sz, 0);
  for (long long i = (0); i <= (sz - 1); i++) {
    long long prime = primes[i];
    if (prime > num)
      return multcities;
    else {
      multcities[i] = getMultiplicity(num, prime);
      long long di = po(prime, multcities[i]);
      num = num / di;
    }
  }
  return multcities;
}
map<long long, long long> getMapPrimeFactorization(long long num,
                                                   vector<long long> &primes) {
  int sz = primes.size();
  map<long long, long long> primeFac;
  for (long long i = (0); i <= (sz - 1); i++) {
    long long prime = primes[i];
    if (prime > num)
      return primeFac;
    else {
      primeFac[prime] = getMultiplicity(num, prime);
      long long di = po(prime, primeFac[prime]);
      num = num / di;
    }
  }
  return primeFac;
}
vector<pair<long long, long long>> getListPrimeFactorization(
    long long num, vector<long long> &primes) {
  int sz = primes.size();
  vector<pair<long long, long long>> primeFac;
  for (long long i = (0); i <= (sz - 1); i++) {
    long long prime = primes[i];
    if (prime > num)
      return primeFac;
    else {
      long long mult = getMultiplicity(num, prime);
      long long di = po(prime, mult);
      num = num / di;
      if (mult > 0) {
        primeFac.push_back(make_pair(prime, mult));
      }
    }
  }
  return primeFac;
}
vector<int> compute_z(string second) {
  int n = second.length();
  vector<int> z(n, 0);
  int l = 0, r = 0;
  z[0] = n;
  for (long long i = (1); i <= (n - 1); i++) {
    if (r < i) {
      l = r = i;
      int j = 0;
      if (second[0] != second[i]) {
        continue;
      }
      while (j < n and second[j] == second[i + j]) {
        j++;
      }
      r = i + j - 1;
      z[i] = r - i + 1;
    } else {
      int beta = r - i + 1;
      int k = i - l;
      if (z[k] < beta) {
        z[i] = z[k];
      } else {
        int j = 0;
        l = i;
        while (r < n and second[r] == second[r - l]) {
          r += 1;
        }
        r -= 1;
        z[i] = r - i + 1;
      }
    }
  }
  return z;
}
vector<int> getOccurences(string second, string t) {
  string comb = t + "$" + second;
  auto z_vals = compute_z(comb);
  int n = second.size();
  int t_sz = t.size();
  vector<int> occ;
  for (long long i = (0); i <= (n - 1); i++) {
    if (z_vals[t_sz + 1 + i] == t_sz) {
      occ.push_back(i);
    }
  }
  return occ;
}
class DSU {
 private:
  vector<int> parent;
  vector<int> size;

 public:
  DSU(int n) {
    parent.resize(n + 5, 0);
    size.resize(n + 5, 0);
    for (long long i = (1); i <= (n); i++) {
      parent[i] = i;
      size[i] = 1;
    }
  }
  vector<int> getParents() { return parent; }
  vector<int> getSizes() { return size; }
  int getRoot(int node) {
    int par = parent[node];
    if (parent[par] == par) {
      return par;
    }
    int root = getRoot(par);
    parent[node] = root;
    return root;
  }
  bool checkSame(int a, int b) { return getRoot(a) == getRoot(b); }
  void connectNodes(int a, int b) {
    int root1 = getRoot(a);
    int root2 = getRoot(b);
    if (size[root1] < size[root2]) {
      swap(root1, root2);
    }
    parent[root2] = root1;
    size[root1] += size[root2];
  }
};
class SegmentTreeNode {
 private:
  long long total;
  long long pendingUpdate;

 public:
  int start, end;
  SegmentTreeNode() : total(0), start(-1), end(-1), pendingUpdate(0) {}
  void assignLeaf(long long value, int start, int end) {
    total = value;
    this->start = start;
    this->end = end;
  }
  void merge(SegmentTreeNode &left, SegmentTreeNode &right) {
    this->start = left.start;
    this->end = right.end;
    long long leftTotal = left.getValue();
    long long rightTotal = right.getValue();
    if (left.ifPendingUpdate()) {
      leftTotal += left.getSegmentSize() * left.getPendingUpdate();
    }
    if (right.ifPendingUpdate()) {
      rightTotal += right.getSegmentSize() * right.getPendingUpdate();
    }
    this->total = leftTotal + rightTotal;
  }
  long long getValue() { return total; }
  long long getPendingUpdate() { return pendingUpdate; }
  bool ifPendingUpdate() { return pendingUpdate != 0; }
  void applyPendingUpdate() {
    this->total += (this->pendingUpdate) * (this->getSegmentSize());
    this->pendingUpdate = 0;
  }
  void addUpdate(long long val) { this->pendingUpdate += val; }
  int getSegmentSize() { return (end - start + 1); }
};
class SegmentTree {
 public:
  int N;
  SegmentTree(vector<long long> &arr) {
    this->N = arr.size();
    this->treeSize = getSegmentTreeSize(this->N);
    nodes.resize(this->treeSize);
    this->buildTree(arr, 1, 0, N - 1);
  }
  void updateRange(int startPos, int endPos, long long val) {
    updateRange(1, startPos, endPos, val);
  }
  long long getValue(int startPos, int endPos) {
    auto res = getValue(1, startPos, endPos);
    return res.getValue();
  }

 private:
  vector<SegmentTreeNode> nodes;
  int treeSize;
  void buildTree(vector<long long> &arr, int stIndex, int left, int right) {
    if (left == right) {
      this->nodes[stIndex].assignLeaf(arr[left], left, right);
      return;
    }
    int mid = (left + right) / 2;
    int leftIndex = 2 * stIndex, rightIndex = leftIndex + 1;
    buildTree(arr, leftIndex, left, mid);
    buildTree(arr, rightIndex, mid + 1, right);
    nodes[stIndex].merge(nodes[leftIndex], nodes[rightIndex]);
  }
  void updateRange(int stIndex, int startPos, int endPos, long long val) {
    if (startPos == nodes[stIndex].start and endPos == nodes[stIndex].end) {
      nodes[stIndex].addUpdate(val);
      return;
    }
    int mid = (nodes[stIndex].start + nodes[stIndex].end) / 2;
    int leftChildIndex = 2 * stIndex, rightChildIndex = leftChildIndex + 1;
    if (endPos <= mid) {
      updateRange(leftChildIndex, startPos, endPos, val);
    } else if (startPos > mid) {
      updateRange(rightChildIndex, startPos, endPos, val);
    } else {
      updateRange(leftChildIndex, startPos, mid, val);
      updateRange(rightChildIndex, mid + 1, endPos, val);
    }
    nodes[stIndex].merge(nodes[leftChildIndex], nodes[rightChildIndex]);
  }
  SegmentTreeNode getValue(int stIndex, int startPos, int endPos) {
    if (startPos == nodes[stIndex].start and endPos == nodes[stIndex].end) {
      auto result = nodes[stIndex];
      if (result.ifPendingUpdate()) result.applyPendingUpdate();
      return result;
    }
    int mid = (nodes[stIndex].start + nodes[stIndex].end) / 2;
    int leftChildIndex = 2 * stIndex, rightChildIndex = leftChildIndex + 1;
    SegmentTreeNode result;
    if (endPos <= mid) {
      result = getValue(leftChildIndex, startPos, endPos);
    } else if (startPos > mid) {
      result = getValue(rightChildIndex, startPos, endPos);
    } else {
      auto leftResult = getValue(leftChildIndex, startPos, mid);
      auto rightResult = getValue(rightChildIndex, mid + 1, endPos);
      result.merge(leftResult, rightResult);
    }
    if (nodes[stIndex].ifPendingUpdate()) {
      result.addUpdate(nodes[stIndex].getPendingUpdate());
      result.applyPendingUpdate();
    }
    return result;
  }
  int getSegmentTreeSize(int N) {
    int first = 1;
    while (first < N) {
      first = first * 2;
    }
    return first * 2;
  }
};
vector<long long> totalBsts(50, 0);
vector<long long> totalBstSumPrefix(50, 0);
vector<vector<long long>> dp(40, vector<long long>(40, -1));
vector<vector<pair<unsigned long long, unsigned long long>>> dp_pair(
    40,
    vector<pair<unsigned long long, unsigned long long>>(40, make_pair(0, 0)));
void preComputeTotals(int n = 40) {
  totalBsts[0] = totalBstSumPrefix[0] = 1;
  for (long long j = (1); j <= (n); j++) {
    for (long long k = (0); k <= (j - 1); k++) {
      totalBsts[j] += totalBsts[k] * totalBsts[j - 1 - k];
    }
  }
}
long long computeAns(int n, int h) {
  if (h <= 0) return totalBsts[n];
  if (n == 0) return (h == 0) ? 1 : 0;
  if (dp[n][h] >= 0) return dp[n][h];
  long long finalAns = 0;
  for (long long j = (1); j <= (n); j++) {
    long long leftAns = computeAns(j - 1, h - 1);
    long long rightAns = computeAns(n - j, h - 1);
    long long leftAnsInverse = totalBsts[j - 1] - leftAns;
    long long rightAnsInverse = totalBsts[n - j] - rightAns;
    long long thisAns = (leftAns * rightAns) + (leftAnsInverse * rightAns) +
                        (leftAns * rightAnsInverse);
    finalAns = finalAns + thisAns;
  }
  dp[n][h] = finalAns;
  return dp[n][h];
}
int main(void) {
  ios_base::sync_with_stdio(false);
  int n, h;
  cin >> n >> h;
  preComputeTotals(35);
  cout << computeAns(n, h);
  return 0;
}
