Friday, August 5, 2016

Roy and alpha-beta trees - Hacker Rank Solution

Roy has taken a liking to the Binary Search Trees(BST). He is interested in knowing the number of ways an array  of integers can be arranged to form a BST. Thus, he tries a few combinations, and notes down the numbers at the odd levels and the numbers at the even levels.

You're given two values, alpha and beta. Can you calculate the sum of Liking of all possible BST's that can be formed from an array of  integers? Liking of each BST is defined as follows
(sum of numbers on even levels * alpha) - (sum of numbers on odd levels * beta)
Note
  • The root element is at level  ( Even )
  • The elements smaller or equal to the parent element are present in the left subtree, elements greater than or equal to the parent element are present in the right subtree. Explained here
If the answer is no less than , output the answer % .
(If the answer is less than , keep adding  until the value turns non negative.)
Input Format 
The first line of input file contains an integer, , denoting the number of test cases to follow. 
Each testcase comprises of  lines. 
The first line contains , the number of integers. 
The second line contains two space separated integers, alpha and beta
The third line contains space separated  integers_, denoting the  integer in array .
Output Format 
Output  lines. Each line contains the answer to its respective test case.
Constraints
 
 
 
Sample Input
4
1
1 1
1
2
1 1
1 2
3
1 1
1 2 3
5
1 1
1 2 3 4 5
Sample Output
1
0
6
54
Explanation
There are  test cases in total.
  • For the first test case, only  BST can be formed with 1 as the root node. Hence the Liking / sum is .
  • For the second test case, we get 2 BSTs of the form, the Liking of the first tree is  and , this sums to , hence the answer.
1                  2 
 \                /
  2              1
  • For the third test case, we get  BSTs. The Liking of each of the BST from left to right are  which sums to  and hence the answer.
1            2                 3          3      1
 \          / \               /          /        \
  2        1   3             1          2          3
   \                          \        /          /
    3                          2      1          2
  • Similarly, for the fourth test case, the answer is .
---------------------------------------------------------------------------------------------------

Roy and alpha-beta trees - Hacker Rank Solution


To solve this problem, firstly you need to understand the very basic structure of BSTs.
Any BST in inorder traversal produces a sorted list of its elements.
So, we can form the inorder taversal first and then try to make the trees that are in agreement to this.
Now, we can iterate over the sorted list and consider all BSTs that can be formed by choosing a particular a[i] as root.
Let us denote the answer for a subarray a[i...j] as ans[i][j].
Now, this problem can be broken into two smaller subproblems.
Suppose, that we are considering an element a[i] as root, then all elements a[0...i-1] shall form the left subtree and all elements a[i+1...n-1] shall form the right subtree.
Then,
ans[i][j] = ans[0][i - 1] * (number of right subtrees) + ans[j + 1][n - 1] * (number of left subtrees) + (contribution from root)
Try to make some samples and convince yourself of this relation. It is to be noted that the root is not considered in any of first 2 terms. This is where alpha, beta comes in.
The contribution of root = (total number of trees) * (alpha | beta) * a[i]
The choice between alpha and beta relies on odd and even levels.
Now, the number of right subtrees and left subtrees can be directly determined using Catalan number
So, we have a final dp state iterating over i as root index
dp[lo][hi][parity] = dp[lo][i-1][!parity] * right_subtree_count 
                    + dp[i+1][hi][!parity] * left_subtree_count 
                    +(left_subtree_count * right_subtree_count * (alpha | beta) * a[i])
Take a look at the setter's solution for a sample implementation.
 Set by Ankit Srivastava
Problem Setter's code :
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

class ANKBST02_solver {
    long go(int lo, int hi, int odd) {
        if (lo > hi) {
            return 0;
        }
        if (dp[lo][hi][odd] == -1) {
            long ans = 0;
            for (int root = lo; root <= hi; root++) {
                //consider all BST in left subtree of root
                ans += (go(lo, root - 1, 1 -odd) * cnt[hi - root - 1 + 1]) % MOD;
                if (ans >= MOD) ans -= MOD;
                if (ans < 0) ans += MOD;
                //consider all BST in right subtree
                ans += (go(root + 1, hi, 1 -odd) * cnt[root - 1 - lo + 1]) % MOD;
                if (ans >= MOD) ans -= MOD;
                if (ans < 0) ans += MOD;
                //totTrees is total number of trees considered
                long totTrees = (cnt[hi - root] * cnt[root - lo]) % MOD;
                //remember to add the root as many times for each tree
                ans += (totTrees * ((mul[odd] * a[root]) % MOD)) % MOD;
                if(ans >= MOD) ans -= MOD;
                if (ans < 0) ans += MOD;
            }
            dp[lo][hi][odd] = ans;
        }
        return dp[lo][hi][odd];
    }

    public void solve() throws IOException {
        cnt = generateCatalan(205, MOD);
        cnt[0] = 1;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);
        int t = Integer.parseInt(br.readLine());

        while (t --> 0) {
            int n = Integer.parseInt(br.readLine());
            assert(n <= 200);
            a = new long[n] ;
            mul = new long[2];
            int i = 0;
            for (StringTokenizer tokenizer = new StringTokenizer(br.readLine()); tokenizer.hasMoreTokens(); ) {
                String s = tokenizer.nextToken();
                mul[i ++] = Integer.parseInt(s);
            }
            mul[1] = -mul[1];
            i = 0;
            for (StringTokenizer tokenizer = new StringTokenizer(br.readLine()); tokenizer.hasMoreTokens(); ) {
                String s = tokenizer.nextToken();
                a[i ++] = Integer.parseInt(s);
            }
            assert(i == n);
            Arrays.sort(a);
            dp = new long[n][n][2];
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    for (int l = 0; l < 2; l++) {
                        dp[j][k][l] = -1;
                    }
                }
            }
            pw.println(go(0, n - 1, 0));
        }
        pw.close();
    }

    long[] a;
    long[][][] dp;
    long[] cnt;
    long MOD = (int) (1e9 + 9);
    long[] mul;

    public static long[] generateCatalan(int n, long module) {
        long[] inv = generateReverse(n + 2, module);
        long[] Catalan = new long[n];
        Catalan[1] = 1;
        for (int i = 1; i < n - 1; i++) {
            Catalan[i + 1] = (((2 * (2 * i + 1) * inv[i + 2]) % module) * Catalan[i]) % module;
        }
        return Catalan;
    }

    public static long[] generateReverse(int upTo, long module) {
        long[] result = new long[upTo];
        if (upTo > 1)
            result[1] = 1;
        for (int i = 2; i < upTo; i++)
            result[i] = (module - module / i * result[((int) (module % i))] % module) % module;
        return result;
    }
}

public class Solution {
    public static void main(String[] args) throws IOException {
            new ANKBST02_solver().solve();
    }
}

No comments:

Post a Comment

Powered by Blogger.