<p>You are given four integers, <code>m</code>, <code>n</code>, <code>introvertsCount</code>, and <code>extrovertsCount</code>. You have an <code>m x n</code> grid, and there are two types of people: introverts and extroverts. There are <code>introvertsCount</code> introverts and <code>extrovertsCount</code> extroverts.</p>

<p>You should decide how many people you want to live in the grid and assign each of them one grid cell. Note that you <strong>do not</strong> have to have all the people living in the grid.</p>

<p>The <strong>happiness</strong> of each person is calculated as follows:</p>

<ul>
	<li>Introverts <strong>start</strong> with <code>120</code> happiness and <strong>lose</strong> <code>30</code> happiness for each neighbor (introvert or extrovert).</li>
	<li>Extroverts <strong>start</strong> with <code>40</code> happiness and <strong>gain</strong> <code>20</code> happiness for each neighbor (introvert or extrovert).</li>
</ul>

<p>Neighbors live in the directly adjacent cells north, east, south, and west of a person&#39;s cell.</p>

<p>The <strong>grid happiness</strong> is the <strong>sum</strong> of each person&#39;s happiness. Return<em> the <strong>maximum possible grid happiness</strong>.</em></p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2020/11/05/grid_happiness.png" style="width: 261px; height: 121px;" />
<pre>
<strong>Input:</strong> m = 2, n = 3, introvertsCount = 1, extrovertsCount = 2
<strong>Output:</strong> 240
<strong>Explanation:</strong> Assume the grid is 1-indexed with coordinates (row, column).
We can put the introvert in cell (1,1) and put the extroverts in cells (1,3) and (2,3).
- Introvert at (1,1) happiness: 120 (starting happiness) - (0 * 30) (0 neighbors) = 120
- Extrovert at (1,3) happiness: 40 (starting happiness) + (1 * 20) (1 neighbor) = 60
- Extrovert at (2,3) happiness: 40 (starting happiness) + (1 * 20) (1 neighbor) = 60
The grid happiness is 120 + 60 + 60 = 240.
The above figure shows the grid in this example with each person&#39;s happiness. The introvert stays in the light green cell while the extroverts live on the light purple cells.
</pre>

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

<pre>
<strong>Input:</strong> m = 3, n = 1, introvertsCount = 2, extrovertsCount = 1
<strong>Output:</strong> 260
<strong>Explanation:</strong> Place the two introverts in (1,1) and (3,1) and the extrovert at (2,1).
- Introvert at (1,1) happiness: 120 (starting happiness) - (1 * 30) (1 neighbor) = 90
- Extrovert at (2,1) happiness: 40 (starting happiness) + (2 * 20) (2 neighbors) = 80
- Introvert at (3,1) happiness: 120 (starting happiness) - (1 * 30) (1 neighbor) = 90
The grid happiness is 90 + 80 + 90 = 260.
</pre>

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

<pre>
<strong>Input:</strong> m = 2, n = 2, introvertsCount = 4, extrovertsCount = 0
<strong>Output:</strong> 240
</pre>

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

<ul>
	<li><code>1 &lt;= m, n &lt;= 5</code></li>
	<li><code>0 &lt;= introvertsCount, extrovertsCount &lt;= min(m * n, 6)</code></li>
</ul>

class Solution:
  def getMaxGridHappiness(
      self,
      m: int,
      n: int,
      introvertsCount: int,
      extrovertsCount: int,
  ) -> int:
    def getPlacementCost(
        i: int,
        j: int,
        inMask: int,
        exMask: int,
        diff: int,
    ) -> int:
      """Calculates the cost based on left and up neighbors.

      The `diff` parameter represents the happiness change due to the current
      placed person in (i, j). We add `diff` each time we encounter a neighbor
      (left or up) who is already placed.

      1. If the neighbor is an introvert, we subtract 30 from cost.
      2. If the neighbor is an extrovert, we add 20 to from cost.
      """
      cost = 0
      if i > 0:
        if (1 << (n - 1)) & inMask:
          cost += diff - 30
        if (1 << (n - 1)) & exMask:
          cost += diff + 20
      if j > 0:
        if 1 & inMask:
          cost += diff - 30
        if 1 & exMask:
          cost += diff + 20
      return cost

    @functools.lru_cache(None)
    def dp(
        pos: int, inMask: int, exMask: int, inCount: int, exCount: int
    ) -> int:
      # `inMask` is the placement of introvert people in the last n cells.
      # e.g. if we have m = 2, n = 3, i = 1, j = 1, then inMask = 0b101 means
      #
      # ? 1 0
      # 1 x ? (x := current position)
      i, j = divmod(pos, n)
      if i == m:
        return 0

      shiftedInMask = (inMask << 1) & ((1 << n) - 1)
      shiftedExMask = (exMask << 1) & ((1 << n) - 1)

      skip = dp(pos + 1, shiftedInMask, shiftedExMask, inCount, exCount)
      placeIntrovert = (
          120 + getPlacementCost(i, j, inMask, exMask, -30) +
          dp(pos + 1, shiftedInMask + 1, shiftedExMask, inCount - 1, exCount)
          if inCount > 0
          else -math.inf)
      placeExtrovert = (
          40 + getPlacementCost(i, j, inMask, exMask, 20) +
          dp(pos + 1, shiftedInMask, shiftedExMask + 1, inCount, exCount - 1)
          if exCount > 0
          else -math.inf)
      return max(skip, placeIntrovert, placeExtrovert)

    return dp(0, 0, 0, introvertsCount, extrovertsCount)
139700