<p>You are given two <strong>0-indexed</strong> arrays <code>nums</code> and <code>cost</code> consisting each of <code>n</code> <strong>positive</strong> integers.</p>

<p>You can do the following operation <strong>any</strong> number of times:</p>

<ul>
	<li>Increase or decrease <strong>any</strong> element of the array <code>nums</code> by <code>1</code>.</li>
</ul>

<p>The cost of doing one operation on the <code>i<sup>th</sup></code> element is <code>cost[i]</code>.</p>

<p>Return <em>the <strong>minimum</strong> total cost such that all the elements of the array </em><code>nums</code><em> become <strong>equal</strong></em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> nums = [1,3,5,2], cost = [2,3,1,14]
<strong>Output:</strong> 8
<strong>Explanation:</strong> We can make all the elements equal to 2 in the following way:
- Increase the 0<sup>th</sup> element one time. The cost is 2.
- Decrease the 1<sup><span style="font-size: 10.8333px;">st</span></sup> element one time. The cost is 3.
- Decrease the 2<sup>nd</sup> element three times. The cost is 1 + 1 + 1 = 3.
The total cost is 2 + 3 + 3 = 8.
It can be shown that we cannot make the array equal with a smaller cost.
</pre>

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

<pre>
<strong>Input:</strong> nums = [2,2,2,2,2], cost = [4,2,8,1,3]
<strong>Output:</strong> 0
<strong>Explanation:</strong> All the elements are already equal, so no operations are needed.
</pre>

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

<ul>
	<li><code>n == nums.length == cost.length</code></li>
	<li><code>1 &lt;= n &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= nums[i], cost[i] &lt;= 10<sup>6</sup></code></li>
	<li>Test cases are generated in a way that the output doesn&#39;t exceed&nbsp;2<sup>53</sup>-1</li>
</ul>

from collections import defaultdict


class Solution:
    def minCost(self, nums: List[int], costs: List[int]) -> int:
        n = len(nums)

        portfolio = defaultdict(int)
        for i in range(n):
            portfolio[nums[i]] += costs[i]

        portfolio = sorted(portfolio.items(), key=lambda x: x[0])

        n = len(portfolio)

        def calc_cost(target):
            cost = 0
            for i in range(n):
                cost += abs(portfolio[i][0] - target) * portfolio[i][1]
            return cost

        l, r = 0, n - 2
        res = float("inf")
        while l <= r:
            mid = (l + r) // 2
            cost1, cost2 = calc_cost(portfolio[mid][0]), calc_cost(
                portfolio[mid + 1][0]
            )
            res = min(res, cost1, cost2)
            if cost1 > cost2:
                l = mid + 1
            else:
                r = mid - 1
        return res if res != float("inf") else 0


class Solution:
    def minCost(self, nums: List[int], cost: List[int]) -> int:
        freq = {}
        stop = sum(cost) // 2
        for n, c in zip(nums, cost):
            freq[n] = freq.get(n, 0) + c

        keys = sorted(list(freq.keys()))
        s = 0
        for k in keys:
            s += freq[k]
            if s > stop:
                break

        result = 0
        for n, c in zip(nums, cost):
            result += abs(n - k) * c

        return result


class Solution:
    def minCost(self, nums: List[int], cost: List[int]) -> int:
        # [5,1,3,2]
        # [1,2,3,14]

        portfolio = defaultdict(int)
        for i in range(len(nums)):
            portfolio[nums[i]] += cost[i]

        portfolio = sorted(portfolio.items(), key=lambda x: x[0])

        n = len(portfolio)

        left = [0] * n
        right = [0] * n
        pre = [0] * (n + 1)
        for i in range(n):
            pre[i + 1] = portfolio[i][1] + pre[i]

        for i in range(1, n):
            left[i] = left[i - 1] + (portfolio[i][0] - portfolio[i - 1][0]) * pre[i]
            j = n - i - 1
            right[j] = right[j + 1] + (portfolio[j + 1][0] - portfolio[j][0]) * (
                pre[n] - pre[j + 1]
            )
        return min([left[i] + right[i] for i in range(n)])

375