#include <vector>
#include <iostream>
#include <math.h>
#include <stdio.h>
#include <string>
#include <stdlib.h>
using namespace std;
static const int STEP = 4;
static const int UNIT = pow(10, STEP);
class Integer
{
public:
Integer(char* buf, int len)
{
int first = len % STEP;
if (first > 0)
{
int x = 0;
for (int j = 0; j < first; ++j)
{
x = x * 10 + buf[j] - '0';
}
m_data.push_back(x);
}
buf += first;
len -= first;
for (int i = 1; i <= len/STEP; ++i)
{
int x = 0;
for (int j = 0; j < STEP; ++j)
{
x = x * 10 + buf[(i - 1) * STEP + j] - '0';
}
m_data.push_back(x);
}
}
Integer() {}
void Print()
{
int cnt = m_data.size();
if (cnt <= 0)
cout << "0";
string format("%0xd");
format[2] = STEP + '0';
for (int i = 0; i < cnt; ++i)
{
if (i == 0)
cout << m_data[i];
else
printf(format.c_str(), m_data[i]);
}
}
public:
void Add(const Integer& other)
{
Integer result;
Add(other, result);
m_data = result.m_data;
}
void Multiply(const Integer& other)
{
Integer result;
Multiply(other, result);
m_data = result.m_data;
}
private:
void Add(const Integer& other, Integer& result) const
{
result.m_data.clear();
int flag = 0;
int i = 0, limit = (other.m_data.size() > m_data.size()) ? other.m_data.size() : m_data.size();
while(i < limit)
{
int num1 = (i < m_data.size()) ? m_data[m_data.size() - 1 - i] : 0;
int num2 = (i < other.m_data.size()) ? other.m_data[other.m_data.size() - 1 - i] : 0;
int sum = num1 + num2 + flag;
flag = sum / UNIT;
result.m_data.push_back(sum % UNIT);
++i;
}
if (flag > 0)
result.m_data.push_back(flag);
result.ShrinkAndInvert();
}
void Minus(const Integer& other, Integer& result) const
{
result.m_data.clear();
int flag = 0;
int i = 0, limit = (other.m_data.size() > m_data.size()) ? other.m_data.size() : m_data.size();
while(i < limit)
{
int num1 = (i < m_data.size()) ? m_data[m_data.size() - 1 - i] : 0;
int num2 = (i < other.m_data.size()) ? other.m_data[other.m_data.size() - 1 - i] : 0;
int left = num1 - flag - num2;
if (left < 0)
{
flag = 1;
left += UNIT;
}
else
flag = 0;
result.m_data.push_back(left);
++i;
}
if (flag < 0)
result.m_data.push_back(UNIT - 1);
result.ShrinkAndInvert();
}
void Multiply(const Integer& other, Integer& result) const
{
result.m_data.clear();
for (int i = other.m_data.size() - 1; i >= 0; --i)
{
Integer tmp, sum;
Multiply(other.m_data[i], tmp, other.m_data.size() - i - 1);
result.Add(tmp, sum);
result = sum;
}
}
void Multiply(const int n, Integer& result, int shift) const
{
result.m_data.clear();
for (int i = 0; i < shift; ++i)
result.m_data.push_back(0);
int flag = 0;
for (int i = m_data.size() - 1; i >= 0; --i)
{
int tmp = m_data[i] * n + flag;
flag = tmp / UNIT;
result.m_data.push_back(tmp % UNIT);
}
if (flag > 0)
result.m_data.push_back(flag);
result.ShrinkAndInvert();
}
void Divide(const Integer& other, Integer& result) const
{
result.m_data.clear();
if (operator == (other))
{
result.m_data.push_back(1);
return;
}
if (!(operator > (other)))
return;
int sizeDev = m_data.size() - other.m_data.size();
Integer tmp = (*this);
Integer resultTmp1, resultTmp2;
for (int i = sizeDev; i >= 0; --i)
{
Integer tmp1, tmp2;
other.Multiply(1, tmp1, i);
int sum = 0;
while(true)
{
if (tmp >= tmp1)
{
tmp.Minus(tmp1, tmp2);
++sum;
tmp = tmp2;
}
else
break;
}
resultTmp1.m_data.clear();
if (sum > 0)
{
for (int j = 0; j < i; ++j)
resultTmp1.m_data.push_back(0);
resultTmp1.m_data.push_back(sum);
resultTmp1.ShrinkAndInvert();
}
result.Add(resultTmp1, resultTmp2);
result = resultTmp2;
}
}
void ShrinkAndInvert()
{
while(m_data.size() != 0)
{
if (m_data[m_data.size() - 1] == 0)
m_data.pop_back();
else
break;
}
int cnt = m_data.size();
for (int i = 0; i < cnt / 2; ++i)
{
int tmp = m_data[i];
m_data[i] = m_data[cnt - 1 - i];
m_data[cnt - 1 - i] = tmp;
}
}
bool operator > (const Integer& other) const
{
if (m_data.size() > other.m_data.size())
return true;
if (m_data.size() < other.m_data.size())
return false;
for (int i = 0; i < m_data.size(); ++i)
if (m_data[i] < other.m_data[i])
return false;
else if (m_data[i] > other.m_data[i])
return true;
return false;
}
bool operator == (const Integer& other) const
{
if (m_data.size() != other.m_data.size())
return false;
for (int i = 0; i < m_data.size(); ++i)
if (m_data[i] != other.m_data[i])
return false;
return true;
}
bool operator >= (const Integer& other) const
{
return ((operator > (other)) || (operator == (other)));
}
private:
vector<int> m_data;
};
#define MAX_PAIRS 150
#define MAX_DEPTH 150
static Integer s_Zero("0", 1);
static Integer s_One("1", 1);
typedef Integer* IntegerPtr;
static IntegerPtr** InitResults()
{
IntegerPtr** results = new IntegerPtr* [MAX_PAIRS + 1];
for (int i = 0; i <= MAX_PAIRS; ++i)
{
results[i] = (IntegerPtr*)calloc(i + 1, sizeof(IntegerPtr));
if (i == 0)
results[0][0] = &s_One;
else
{
results[i][0] = &s_Zero;
results[i][1] = &s_One;
results[i][i] = &s_One;
}
}
return results;
}
static void DeleteResults(IntegerPtr** results)
{
for (int i = 0; i <= MAX_PAIRS; ++i)
{
for (int j = 0; j <= i; ++j)
{
IntegerPtr pResult = results[i][j];
if ((pResult != (&s_Zero)) &&
(pResult != (&s_One)))
delete pResult;
}
free(results[i]);
}
delete[] results;
}
static IntegerPtr** InitSumsByDepth()
{
IntegerPtr** sumsByDepth = new IntegerPtr* [MAX_PAIRS + 1];
for (int i = 0; i <= MAX_PAIRS; ++i)
{
sumsByDepth[i] = (IntegerPtr*)calloc(i + 1, sizeof(IntegerPtr));
if (i == 0)
sumsByDepth[0][0] = &s_One;
else
{
sumsByDepth[i][0] = &s_Zero;
sumsByDepth[i][1] = &s_One;
}
}
return sumsByDepth;
}
static void DeleteSumsByDepth(IntegerPtr** sumsByDepth)
{
for (int i = 0; i <= MAX_PAIRS; ++i)
{
for (int j = 0; j <= i; ++j)
{
IntegerPtr pResult = sumsByDepth[i][j];
if ((pResult != (&s_Zero)) &&
(pResult != (&s_One)))
delete pResult;
}
free(sumsByDepth[i]);
}
delete[] sumsByDepth;
}
static IntegerPtr GetResult(int pairs, int depth, IntegerPtr** results, IntegerPtr** sumsByDepth);
static IntegerPtr GetSumsByDepth(
int pairs, int depth, IntegerPtr** results, IntegerPtr** sumsByDepth)
{
if (depth > pairs)
depth = pairs;
if (sumsByDepth[pairs][depth] != NULL)
return sumsByDepth[pairs][depth];
IntegerPtr result = new Integer("0", 1);
result->Add(*GetSumsByDepth(pairs, depth - 1, results, sumsByDepth));
if (depth <= pairs)
{
if (depth == pairs)
result->Add(s_One);
else
result->Add(*GetResult(pairs, depth, results, sumsByDepth));
}
sumsByDepth[pairs][depth] = result;
return result;
}
static IntegerPtr GetResult(int pairs, int depth, IntegerPtr** results, IntegerPtr** sumsByDepth)
{
if (depth > pairs)
return &s_Zero;
if (depth == pairs)
return &s_One;
if (results[pairs][depth] != NULL)
return results[pairs][depth];
// F(n,d): How many legal combinations for n pairs of brackets with depth as d.
// F(n,d) = Sum(k = 0 to n-1){ F(k,d-1)*Sum(i = 0 to d){F(n-k-1,i)} + F(n-k-1, d)*Sum(i = 0 to d-2){F(k,i)} }
IntegerPtr finalResult = new Integer("0", 1);
for (int k = 0; k <= pairs - 1; ++k)
{
if (depth - 1 <= k)
{
Integer tempResult("0", 1);
tempResult.Add(*GetSumsByDepth(pairs - k - 1, depth, results, sumsByDepth));
if ((depth != 2) && (depth != (k + 1)))
tempResult.Multiply(*GetResult(k, depth - 1, results, sumsByDepth));
finalResult->Add(tempResult);
}
if (depth <= (pairs - k - 1))
{
Integer tempResult("0", 1);
tempResult.Add(*GetSumsByDepth(k, depth - 2, results, sumsByDepth));
if ((depth != 1) && (depth != (pairs - k - 1)))
tempResult.Multiply(*GetResult(pairs - k - 1, depth, results, sumsByDepth));
finalResult->Add(tempResult);
}
}
results[pairs][depth] = finalResult;
return finalResult;
}
static void DoTest(int n, int d, IntegerPtr** results, IntegerPtr** sumsByDepth)
{
if (((n % 2) != 0) || (d > (n/2)))
{
cout << '0';
return;
}
if ((d == (n/2)) || (d == 1))
{
cout << '1';
return;
}
IntegerPtr result = GetResult(n/2, d, results, sumsByDepth);
result->Print();
}
static void Test()
{
IntegerPtr** results = InitResults();
IntegerPtr** sumsByDepth = InitSumsByDepth();
int n, d;
while (cin >> n >> d)
{
DoTest(n, d, results, sumsByDepth);
cout << endl;
}
DeleteResults(results);
DeleteSumsByDepth(sumsByDepth);
}
int main(int argc, char* argv[])
{
Test();
return 0;
}