Python DP with (perhaps too detailed) explanation (99% speed)
[Observation 1] \nGiven positive integers a, b, and c, if c = a * b, then c >= a and c >= b. Thus, only larger numbers can have children consisting of smaller n
**[Observation 1]** \nGiven positive integers `a`, `b`, and `c`, if `c = a * b`, then `c >= a` and `c >= b`. Thus, only larger numbers can have children consisting of smaller numbers.\n**[Strategy 1]** \nWe first compute the valid trees with smaller numbers as the topmost parent, then append these trees as children to a larger number and see if they remain valid. In other words: we scan from small numbers to large numbers, and at each number (outer loop), we look back and see if there were some smaller numbers (inner loop) being the divisor as our current number. Therefore it\'s a DP problem.\n\n**[Observation 2]** For positive integers `a`, `b`, and `c`, if `a * b = c` and `a <= b`, then the possibilities are:\n` 1 * b = c      ->       b = c`\n` 2 * b = c      ->       b = c/2`\n` 3 * b = c      ->       b = c/3`\n` 4 * b = c      ->       b = c/4`\n`...`\nOf course these may not all be true, depending on whether `c` really has 2, 3, 4, ... as its divisors, but you can see besides `b = c`, the largest possible value for b is no larger than `c/2`.\n**[Strategy 2]** Given a current number `i` (outer loop), when we look back to smaller numbers (inner loop), we skip those that are greater than `i/2`.\n\n**[Observation 3]** Let `c = a * b` and let the numbers of possible trees for `a` and `b` be `na` and `nb`, respectively. If `a == b`, there\'s only one way to append the trees: append `a(==b)` to both the left and the right. The total number of possible configurations is `na * na == nb * nb`.\nHowever if `a != b`, then there are two ways to append the `a` and `b` trees to `c`, namely (1) `a` to the left and `b` to the right and (2) `a` to the right and `b` to the left. The total number of possible ways to append is then `na * nb * 2`.\n**[Strategy 3]** The implication is that if we have `c = a * b` and `a < b`, then we will meet `a` in our inner loop first (because `a` is smaller), and we don\'t need to check `b` later because we already take into account the configurations including `b` when we first meet `a`. Therefore, if at some `a` we find `a > c / a`, we can break out of the inner loop to save time.\n\n**[Code]**\n```\nclass Solution:\n    def numFactoredBinaryTrees(self, arr: List[int]) -> int:\n        arr.sort()\n\t\t# use a hashmap to quickly look up checked numbers\n\t\t# {key: value} = {n: number of trees with n as its topmost parent}\n        d = {}\n\t\t# observation 1\n        for i in arr: # outer loop\n\t\t\t# an isolated i itself is always a valid tree\n            d[i] = 1\n            for j in arr: # inner loop\n\t\t\t\t# observation 2 & 3\n                if j == i or j > i//2+1 or j > i//j: break\n\t\t\t\t# observation 3\n                if i%j == 0 and i//j in d:\n                    if j == i//j:\n                        d[i] = d[i] + d[j]*d[i//j]\n                    else:\n                        d[i] = d[i] + d[j]*d[i//j]*2\n        return sum(d.values())%(10**9+7)\n```\n\nTime complexity: O(N^2)\nSpace complexity: O(N)
['Dynamic Programming', 'Python']