📌  相关文章
📜  X 的最小值,使得 arr[i] – X 的 brr[i] 次方之和小于或等于 K(1)

📅  最后修改于: 2023-12-03 15:06:03.878000             🧑  作者: Mango

找到 X 的最小值

给定一个整数数组 arr 和一个整数数组 brr,以及一个整数 K。求 X 的最小值,使得 $\sum_{i=0}^{n-1}{(arr[i] - X)^{brr[i]}} \leq K$。

解法

为了简化计算,我们可以将 $arr[i]$ 按非降序排序。此时,对于每个 $i$,如果对于所有满足 $j < i$ 的 $j$,均有 $arr[j] - X \leq arr[i] - X$,那么可以把 $arr[i]$ 看作是所有 $arr[j]$ 的下限。此时,如果 $X$ 越大,更新的值也越大,即更新函数是单调的。那么我们可以二分最优的 $X$。

假设我们要求二分左端点 $l$ 和右端点 $r$,二分过程中维护一个变量 $sum$(即 $\sum_{i=0}^{n-1}{(arr[i] - X)^{brr[i]}}$)。对于每次的二分尝试,如果 $sum \leq K$,则更新左端点 $l$;否则更新右端点 $r$。当 $r-l=1$ 时,即找到了最小的 $X$,再返回 $l$ 即可。

由于求幂操作是 $O(\log brr_i)$ 的,总的时间复杂度是 $O(n \log^2 n)$。可以通过将 log 小定值来进行优化。

代码
def findX(arr, brr, K):
    n = len(arr)
    arr_brr = list(zip(arr, brr))
    arr_brr.sort()

    def calc_sum(x):
        s = 0
        for i in range(n):
            s += (arr_brr[i][0] - x) ** arr_brr[i][1]
        return s

    l, r = arr_brr[0][0], arr_brr[-1][0]
    while l < r - 1:
        mid = (l + r) // 2
        if calc_sum(mid) > K:
            l = mid
        else:
            r = mid
    if calc_sum(l) <= K:
        return l
    else:
        return r