def solution(l):
    """
    Solution 4 again passes all but the last test case.  Try to speed things
    up some using a dynamic programming-like approach.

    This solution wound up passing all of the test cases -- the key here is to
    uses a memorization/dynamic programming approach.  A core component of this
    problem involves finding all multiples of a number after a given number in
    the list.  In the brute force approach, we do the following:

    0: for each li:
        1: for each lj such that j > i:
            2: if li divides lj:
                3: for each lk such that k > j:
                    4: if lj divides lk:
                        (li, lj, lk) is a valid solution

    Note that steps 3 and 4 involve counting the number of valid values of lk
    for a given lj.  Since we are evaluating all possible values of lj for each
    possible value of li, this means that we would potentially repeat steps 3
    and 4 multiple times for the *same value of lj*.

    Take the example:
    l = [1, 1, 1, 1, 3]
    In this case we would evaluate the number of valid lks for the final '1'
    3 times.  In the worst case, where l is of length N and consists of
    all 1's, we would be finding the valid lks for the penultimate lj (N-2)
    times.

    To improve on this, we can cache/memorize the values as we compute them.
    We'll store the smallest computation -- the number of possible values of lk
    for a given lj.  Then, as we traverse the list, if we have already
    computed the values of lk for a given lj, we just use the value that we
    previously computed.  This touches on the concept of Dynamic Programming.
    """
    # Make sure no numbers are less than 1 or greater than 999999
    for li in l:
        if li > 999999 or li < 1:
            return 0

    # Get number of elements in the list
    n_l = len(l)

    # If there are fewer than 3 elements in the list, then there
    # can't be any lucky triples, so return 0
    if n_l < 3 or n_l > 2000:
        return 0

    # Initialize counts -- d_cts[j] corresponds to the number of valid values
    # of l[k] for l[j].
    d_cts = [-1] * n_l

    ctr = 0
    # First iterate over i
    for i in range(n_l-2):
        for j in range(i+1, n_l-1):
            if l[j] % l[i] == 0:
                # Check to see if we already computed this
                if d_cts[j] == -1:
                    # Count the number of valid divisors for l[j]
                    d_ctr = 0
                    for k in range(j+1, n_l):
                        if l[k] % l[j] == 0:
                            d_ctr += 1
                        d_cts[j] = d_ctr

                # Add the pre-computed value
                ctr += d_cts[j]

    return ctr