• + 0 comments

    Python3 solution

    # Enter your code here. Read input from STDIN. Print output to STDOUT
    
    '''
    Over all possible rooted trees of n vertices, how many possible outputs can the DFS() function yield that match array S? (I renamed A to S instead)
    
    The output array delineates the depths of the nodes as it traverses depth-first. For example
    
            o            Depth 0
          /   \
         o     o         Depth 1
        / \     \
       o   o     o       Depth 2
                / \
               o   o     Depth 3
              /|\   \
             o o o   o   Depth 4
       
    yields order [0,1,2,2,1,2,3,4,4,4,3,4]
    
    Necessary conditions: 
    
    1. Clearly, there is only one root node, and its depth is 0, so 0 must be at the start of S, either in the form of a "?" or a 0.
    2. 0 cannot be present anywhere in S other than the very front.
    3. If the search traverses from parent to child, the depth increases by 1.
    4. If we hop to another child or subtree instead, its depth can only be less than or equal to current depth
    
    In other words, we are counting the number of sequences (that match S) such that a value can increase by at most 1, or drop down to any positive integer. So:
    1. output[0] = 0
    2. output[i] - 1 <= output[i-1]
    
    So when looking at S, let's look at sequences of ? characters between fixed elements. For example:
    [...,5,?,?,?,?,?,?,?,?,?,?,8,...]
    Let a=5 and b=8. Let n = 10, the number of "?" between a and b.
    The first ? must start with some number in the range [1 to a+1] => [1 to 6] inclusive.
    The last ? must be in the range [max(1,b-1) to (a + n)] => [7 to 15] inclusive.
    How many valid sequences are there? 
    In general, comb(2*n+a-b+1,n) - comb(2*n+a-b+1,n-b)
    '''
    
    import sys
    
    MOD = 10 ** 9 + 7
    MAXN = 10 ** 5
    MAXAI = 200
    factLim = 2 * MAXN + MAXAI
    fact = [1] + [0] * (factLim)
    for i in range(1, factLim + 1):
        fact[i] = fact[i - 1] * i % MOD
        
    def comb(n, k):
        if k < 0 or n < 0 or k > n: return 0
        if k == 0 or k == n: return 1
        return fact[n] * pow(fact[k] * fact[n - k], MOD - 2, MOD) % MOD
    
    def preliminaryCheck_isInvalid(S,N):
        #if first char isn't a 0 or '?', it's some other number. Invalid!
        if S[0] != "?" and S[0] != 0: 
            return True
        for i in range(1, N):
            #if S[i] could not possibly be as high as it is. Invalid!
            if S[i] != "?" and S[i] > i: 
                return True
            #if there's a 0 anywhere else other than the start. Invalid!
            if S[i] == 0: 
                return True
            #Cannot make a depth jump like this. Invalid!
            if (S[i] != "?" and S[i - 1] != "?") and S[i] - 1 > S[i - 1]: 
                return True
        #basic checks OK
        return False  
    
    #number of valid sequences to fill a section of L "?"s between two numbers a and b
    #such that S[i] takes on any number from 1 to S[i-1]+1
    def numQuestionSeq(a, b, n): 
        return comb(2 * n + a - b + 1, n) - comb(2 * n + a - b + 1, n - b)
    
    def numSuitable(S, N):
        if preliminaryCheck_isInvalid(S, N): 
            return 0
        S[0] = 0
        #the extra 1 gives bIndex a sentinel val to use later. N will not count this.
        S += [1]  
        aIndex = 0
        bIndex = 1
        ans = 1
        while aIndex < N and bIndex < N:
            while bIndex < N and S[bIndex] == "?":
                bIndex += 1
            n = bIndex - aIndex - 1
            a, b = S[aIndex], S[bIndex] 
            if n > 0: ans = ans * numQuestionSeq(a, b, n) % MOD
            aIndex = bIndex
            bIndex += 1   
        return ans
    
    N = int(sys.stdin.readline())
    S = [int(k) if k.isdigit() else k for k in sys.stdin.readline().split()]
    print(numSuitable(S,N))