<p>You have a <code>grid</code> of size <code>n x 3</code> and you want to paint each cell of the grid with exactly one of the three colors: <strong>Red</strong>, <strong>Yellow,</strong> or <strong>Green</strong> while making sure that no two adjacent cells have the same color (i.e., no two cells that share vertical or horizontal sides have the same color).</p>

<p>Given <code>n</code> the number of rows of the grid, return <em>the number of ways</em> you can paint this <code>grid</code>. As the answer may grow large, the answer <strong>must be</strong> computed modulo <code>10<sup>9</sup> + 7</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/03/26/e1.png" style="width: 400px; height: 257px;" />
<pre>
<strong>Input:</strong> n = 1
<strong>Output:</strong> 12
<strong>Explanation:</strong> There are 12 possible way to paint the grid as shown.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> n = 5000
<strong>Output:</strong> 30228214
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>n == grid.length</code></li>
	<li><code>1 &lt;= n &lt;= 5000</code></li>
</ul>

class Solution:
    def numOfWays(self, n: int) -> int:
        
        
        MOD = 10 ** 9 + 7
        def all_perm(i,cand):
            if i == 2:
                return [[cander] for cander in cand]
            else:
                res = []
                for index in range(len(cand)):
                    cur_start = cand[index]
                    cur_perms = all_perm(i + 1, cand)
                    cur_perms = [[cur_start] + member for member in cur_perms]
                    res += cur_perms
                return res
        
        perms = all_perm(0, ['0','1','2'])
        
        perms = [''.join(perm) for perm in perms]

        @cache
        def check_valid(last_row, this_row):
            for i in range(2):
                if last_row[i + 1] == last_row[i]:
                    return False
            for i in range(2):
                if this_row[i + 1] == this_row[i]:
                    return False
            
            for i in range(len(this_row)):
                if last_row[i] == this_row[i]:
                    return False
            return True
            
                    
        @cache
        def niggerize(pattern):
            if pattern != None:
                res = []
                for perm in perms:
                    if check_valid(pattern, perm):
                        res.append(perm)
                return res
            else:
                res = []
                for perm in perms:
                    is_valid = True
                    for i in range(2):
                        if perm[i + 1] == perm[i]:
                            is_valid = False
                            break
                    if is_valid:
                        res.append(perm)
                return res
        
        @cache
        def dp(i, last_row):
            if i == 1:
                candidates = niggerize(last_row)
                return len(candidates)   
            elif last_row == None:
                res = 0
                for perm in perms:
                    is_valid = True
                    for index in range(2):
                        if perm[index + 1] == perm[index]:
                            is_valid = False
                            break
                    if is_valid:
                        res += dp(i - 1, perm)
                        res %= MOD
                return res
   
            else:
                res = 0
                candidates = niggerize(last_row)
                for perm in candidates:
                        res += dp(i - 1, perm)
                        res %= MOD
                return res
        
        return dp(n, None)
                    
                            
                    
                    
            
            
41600