Skip to content

3562. Maximum Profit from Trading Stocks with Discounts 👍

  • Time:
  • Space:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class Solution:
  def maxProfit(
      self,
      n: int,
      present: list[int],
      future: list[int],
      hierarchy: list[list[int]],
      budget: int,
  ) -> int:
    tree = [[] for _ in range(n)]

    for u, v in hierarchy:
      tree[u - 1].append(v - 1)

    @functools.lru_cache(None)
    def dp(u: int, parent: int) -> tuple[list[int], list[int]]:
      noDiscount = [0] * (budget + 1)
      withDiscount = [0] * (budget + 1)

      for v in tree[u]:
        if v == parent:
          continue
        childNoDiscount, childWithDiscount = dp(v, u)
        noDiscount = self._merge(noDiscount, childNoDiscount)
        withDiscount = self._merge(withDiscount, childWithDiscount)

      newDp0 = noDiscount[:]
      newDp1 = noDiscount[:]

      # 1. Buy current node at full cost (no discount)
      fullCost = present[u]
      for b in range(fullCost, budget + 1):
        profit = future[u] - fullCost
        newDp0[b] = max(newDp0[b], withDiscount[b - fullCost] + profit)

      # 2. Buy current node at half cost (discounted by parent)
      halfCost = present[u] // 2
      for b in range(halfCost, budget + 1):
        profit = future[u] - halfCost
        newDp1[b] = max(newDp1[b], withDiscount[b - halfCost] + profit)

      return newDp0, newDp1

    return max(dp(0, -1)[0])

  def _merge(self, dpA: list[int], dpB: list[int]) -> list[int]:
    merged = [-math.inf] * len(dpA)
    for i, a in enumerate(dpA):
      for j in range(len(dpA) - i):
        merged[i + j] = max(merged[i + j], a + dpB[j])
    return merged