401. Sharik’s Letter from Prostokvashino

 

“Dear Uncle Fedor!

Do not listen to this old grumpy cat. He does not know what surprise I have prepared for him, so you can begin to write a program for him. I increased the number of brackets for him up to 300, the number of jobs per day up to 20, and complicated the task itself.  

Now he must find the depth of the correctly formed bracket expression . What does it mean I read in one clever book which was lost by post officer Pechkin. The following was written there:

“Let X is a set of correctly formed bracket expressions. The length of the correctly formed expression E is the number of single brackets in E. The bracket depth D(E) of expression E is defined as follows:

For example, the length of ( )(( ))( ) is 8, and the depth is 2.”

Understanding that the cat is not a man, I give him such tasks, where the depth of expression is at least 1 and no more than 200, and at least 2 squares with brackets. Now let he find the number of ways to get the correct bracket sequence with given length and depth.

So hurry to send him your new program, because now I am milking a cow only until Matroskin is busy computing. Photo of thoughtful Matroskin is attached.

Your faithful friend and companion – Sharik”

 

Input. Each line contains two numbers n and d, where n is the number of squares with parentheses, and d is the depth of expression. Input can contain empty lines, ignore them.

 

Output. For each test case print in a separate line the number of ways to obtain the correctly formed bracket expression of length n and depth d.

 

Sample input

Sample output

6 2

300 150

3

1

 

 

SOLUTION

dynamic programming

 

Algorithm analysis

Any non-empty bracket expression A of length n and depth no greater than d can be expressed as (X)Y, where X and Y some expressions, possibly empty. Let the length of expression (X) equals to k. Then the length of X is k – 2, and the length of Y is nk. Obviously that 2 ≤ kn and k can take only even values. When k = 2 the expression X is empty, and when k = n the expression Y is empty. Note also, since the depth of expression A is not greater than d, then the depth of X is not greater than d – 1, and the depth of Y is not greater than d.

Denote f(n, d) the number of ways to get a well-formed bracket expression of length n and depth not greater than d. Then we have f(k – 2, d – 1) ways to represent the expression X and f(nk, d) ways to represent the expression Y. Using the multiplication rule we can say that for a fixed k the expression (X)Y can be represented in f(k – 2, d – 1) * f(nk, d) ways. So

f(n, d) =

Since the problem requires to find the number of ways to get a well-formed bracket expression of length n and depth exactly d, then the answer will g(n, d) = f(n, d) – f(n, d – 1).

Separately you must handle the following cases:

·        If d > n / 2, then g(n, d) = 0;

·        If d = n / 2, then we have a unique bracket expression (((…))), so g(n, n / 2) = 1;

·        If d = 1, then we have a unique bracket expression ()()…()(), so g(n, 1) = 1;

 

Example

f(2, 2) =  = f(0, 1) * f(0, 2) = 1* 1 = 1. If one can represent the bracket expression of length 2 and depth not greater than 2 as (X)Y, then the factor f(0, 1) corresponds to the number of ways to represent X, and the factor f(0, 2) corresponds to the number of ways to represent Y. These factors equal to one, and X and Y corresponds an empty expression. So for f(2, 2) corresponds only one expression ().

f(4, 2) =  =

f(0, 1) * f(2, 2) + f(2, 1) * f(0, 2) = 1 * 1 + 1 * 1 = 2

The summand f(0, 1) * f(2, 2) corresponds to expression ()(), and the summand f(2, 1) * f(0, 2) corresponds to expression (()).

f(6, 2) =  =

f(0, 1) * f(4, 2) + f(2, 1) * f(2, 2) + f(4, 1) * f(0, 2) = 1 * 2 + 1 * 1 + 1 * 1 = 4

 

Summand

The corresponding bracket expressions

f(0, 1) * f(4, 2)

()()(), ()(())

f(2, 1) * f(2, 2)

(())()

f(4, 1) * f(0, 2)

(()())

 

The number of correctly formed bracket expressions of length 6 and of depth exactly 2 equals to

g(6, 2) = f(6, 2) – f(6, 1) = 4 – 1 = 3

They are: ()(()),(())(),(()()).

 

Algorithm realization

The value f(n, d) we shall keep in array of long numbers ff.

 

BigInteger ff[301][151];

 

The function f computes the value f(n, d). Separately handle the cases when n < 0 or d < 0 (the function f returns 0). If n = 0, then f(0, d) is assumed to be equal to 1 for any d (this is the case when either X or Y is empty).

 

BigInteger f(long long n, long long d)

{

  long long k;

  BigInteger &s = ff[n][d];

  if ((n < 0) || (d < 0)) return 0;

  if (!n) return ff[n][d] = BigInteger(1);

  if (ff[n][d] >= 0) return ff[n][d];

  for(s = 0, k = 2; k <= n; k += 2)

    s = s + f(k - 2,d - 1) * f(n - k,d);

  return s;

}

 

The main part of the program. First handle the special cases.

 

memset(ff,-1,sizeof(ff));

while(scanf("%lld %lld",&n,&d) == 2)

{

   if (d > n / 2) res = BigInteger(0); else

   if ((d == n / 2) || (d == 1)) res = BigInteger(1); else

   res = f(n,d) - f(n,d-1);

   res.print();printf("\n");

}

 

Java realization

 

import java.util.*;

import java.math.*;

 

public class Main

{

  static BigInteger dp[][];

 

  static BigInteger f(int n, int d)

  {

    BigInteger s = BigInteger.ZERO;

    if ((n < 0) || (d < 0)) return BigInteger.ZERO;

    if (n == 0) return dp[n][d] = BigInteger.ONE;

    if (dp[n][d].compareTo(BigInteger.ZERO) >= 0) return dp[n][d];

    for(int k = 2; k <= n; k += 2)

      s = s.add(f(k - 2,d - 1).multiply(f(n - k,d)));

    return dp[n][d] = s;

  }

 

  public static void main(String[] args)

  {

    Scanner con = new Scanner(System.in);

    while(con.hasNextInt())

    {

      int n = con.nextInt();

      int d = con.nextInt();

      dp = new BigInteger[n+1][d+1];

     

      for(int i = 0; i <= n; i++)

      for(int j = 0; j <= d; j++)

        dp[i][j] = new BigInteger("-1");

     

      BigInteger res = new BigInteger("0");

     

      if (d > n / 2) res = BigInteger.ZERO; else

      if ((d == n / 2) || (d == 1)) res = BigInteger.ONE; else

      res = f(n,d).subtract(f(n,d-1));         

     

      System.out.println(res);     

    }

    con.close();

  }

}