最小差值

最小差值

题目描述

给你一个由 $n$ 个整数组成的数组 $\{a_1,a_2,\dots,a_n\}$,以及一个由 $m$ 个整数组成的数组 $\{b_1,b_2,\dots,b_m\}$,现在我们需要寻找一个最小的整数 $k$,满足 $-2 \times 10^9 \leq k \leq 2 \times 10^9$,使得下式达到最小:$$\left \lvert \bigg(\sum\limits_{i=1}^{n}\left \lvert a_i - k \right \rvert\bigg) - \bigg(\sum\limits_{j=1}^{m}\left \lvert b_j - k \right \rvert\bigg) \right \rvert$$

直接输出满足条件的最小 $k$ 即可。

输入描述:

第一行输入两个整数 $n,m\left(1\leq n,m\leq 10^6\right)$ 代表数组 $a$ 中的元素个数、数组 $b$ 中的元素个数。

第二行输入 $n$ 个整数 $a_1,a_2,\dots,a_n\left(-10^9\leq a_i\leq 10^9\right)$。

第三行输入 $m$ 个整数 $b_1,b_2,\dots,b_m\left(-10^9\leq b_j\leq 10^9\right)$。

输出描述:

直接输出满足条件的最小 $k$ 即可。

示例1

输入

5 5
1 2 3 4 5
1 2 3 4 5

输出

-2000000000

说明

在这个样例中,我们会发现,$k$ 的取值不影响最后的答案,所以选择最小的 $k=-2\times 10^9$ 即可。

示例2

输入

5 3
1 5 9 3 6
2 5 10

输出

3

说明

在这个样例中,$k=3$ 时,有:$$\begin{aligned}\begin{aligned}\bigg(\sum\limits_{i=1}^{5}\left \lvert a_i - 3 \right \rvert\bigg) &= \left \lvert 1 - 3 \right \rvert + \left \lvert 5 - 3 \right \rvert + \left \lvert 9 - 3 \right \rvert + \left \lvert 3 - 3 \right \rvert + \left \lvert 6 - 3 \right \rvert \\&= 2 + 2 + 6 + 0 + 3 \\&= 13\end{aligned}\\\begin{aligned}\bigg(\sum\limits_{j=1}^{3}\left \lvert b_j - 3 \right \rvert\bigg) &= \left \lvert 2 - 3 \right \rvert + \left \lvert 5 - 3 \right \rvert + \left \lvert 10 - 3 \right \rvert \\&= 1 + 2 + 7 \\&= 10\end{aligned}\end{aligned}$$

综上,式子的答案为 $\left \lvert 13 - 10 \right \rvert = 3$,我们可以证明,无法再找到一个 $-2\times 10^9\leq k\leq 3$,使得式子的值 $\le 3$。

 

解题思路

  由于排序不影响结果,为了方便先对数组 $a$ 和 $b$ 从小到大排序。我们可以枚举每一个 $k$ 来求式子的最小值,但细想一下会发现,当 $k$ 落在某个范围内时,式子的结果是不变的。具体来说,我们把数组 $a$ 和 $b$ 进行合并同时从小到大排序,得到数组 $p$。对于任意 $k \in [p_i, p_{i+1}]$ 时,此时 $k$ 必然是 $a$ 的两个相邻元素之间的某个值,同时也是 $b$ 的两个相邻元素之间的某个值,此时 $\bigg(\sum\limits_{i=1}^{n}\left \lvert a_i - k \right \rvert\bigg)$ 和 $\bigg(\sum\limits_{j=1}^{m}\left \lvert b_j - k \right \rvert\bigg)$ 的结果都相同,因此式子不变。

  这启发我们只需关注每一段 $[p_i, p_{i+1}], \, (1 \leq i < n+m)$ 即可。假设当前枚举到第 $i$ 段 $[p_i, p_{i+1}]$,为了描述把式子中的 $k$ 换成 $x$,此时 $x \, (p_i \leq x \leq p_{i+1})$ 应该取值多少,才能使得式子有最小值?假设 $a$ 中有 $c_a$ 个元素小于等于 $x$(意味着 $n - c_a$ 个元素大于 $x$),$b$ 中有 $c_b$ 个元素小于等于 $x$(意味着 $m - c_b$ 个元素大于 $x$)。此时式子的结果等于

\begin{align*}
&\left \lvert \bigg(\sum\limits_{i=1}^{n}\left \lvert a_i - x \right \rvert\bigg) - \bigg(\sum\limits_{j=1}^{m}\left \lvert b_j - x \right \rvert\bigg) \right \rvert \\
= &\left \lvert \sum\limits_{i=1}^{c_a}{x-a_i} + \sum\limits_{i=c_a+1}^{n}{a_i-x} - \left( \sum\limits_{i=1}^{c_b}{x-b_i} + \sum\limits_{i=c_b+1}^{m}{b_i-x} \right) \right \rvert \\
= &\left \lvert c_ax - \sum\limits_{i=1}^{c_a}{a_i} + \sum\limits_{i=c_a+1}^{n}{a_i} - (n-c_a)x - \left( c_bx - \sum\limits_{i=1}^{c_b}{b_i} + \sum\limits_{i=c_b+1}^{m}{b_i} - (m-c_b)x \right) \right \rvert \\
= &\left \lvert \left(c_a - (n - c_a) + (m - c_b) - c_b\right)x + \left(- \sum\limits_{i=1}^{c_a}{a_i} + \sum\limits_{i=c_a+1}^{n}{a_i}- \sum\limits_{i=1}^{c_b}{b_i} + \sum\limits_{i=c_b+1}^{m}{b_i} \right) \right \rvert \\
\end{align*}

  记 $k = \left(c_a - (n - c_a) + (m - c_b) - c_b\right)$,$b = \left(- \sum\limits_{i=1}^{c_a}{a_i} + \sum\limits_{i=c_a+1}^{n}{a_i}- \sum\limits_{i=1}^{c_b}{b_i} + \sum\limits_{i=c_b+1}^{m}{b_i} \right)$,因此就是求折线 $|kx+b|$ 的最小值。

  只需分情况讨论即可,首先是两个端点 $p_i$ 和 $p_{i+1}$。然后是可能的最小点 $kx+b = 0 \Rightarrow x = \frac{-b}{k}$,由于 $x$ 是整数,因此需要考虑以下三个取值,$\left \lfloor \frac{-b}{k} \right \rfloor-1$、$\left \lfloor \frac{-b}{k} \right \rfloor$、$\left \lfloor \frac{-b}{k} \right \rfloor +1$(同时需要保证 $p_i \leq x \leq p_{i+1}$)。

  AC 代码如下,时间复杂度为 $O((n+m)\log{(n+m)})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e6 + 5, M = N * 2;

int a[N], b[N];
LL sa[N], sb[N];
array<int, 2> p[M];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++) {
        cin >> b[i];
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + m + 1);
    for (int i = 1; i <= n; i++) {
        sa[i] = sa[i - 1] + a[i];
    }
    for (int i = 1; i <= m; i++) {
        sb[i] = sb[i - 1] + b[i];
    }
    int sz = 0;
    for (int i = 1; i <= n; i++) {
        p[sz++] = {a[i], 0};
    }
    for (int i = 1; i <= m; i++) {
        p[sz++] = {b[i], 1};
    }
    p[sz++] = {int(-2e9), -1};
    p[sz++] = {int(2e9), -1};
    sort(p, p + sz);
    LL mn = 1e18, ret;
    for (int i = 0, ca = 0, cb = 0; i + 1 < sz; i++) {
        if (!p[i][1]) ca++;
        else if (p[i][1] == 1) cb++;
        LL k = ca - (n - ca) + (m - cb) - cb, b = sa[n] - 2 * sa[ca] + 2 * sb[cb] - sb[m];
        auto get = [&](LL x) {
            if (x < p[i][0] || x > p[i + 1][0]) return;
            if (abs(k * x + b) < mn) {
                mn = abs(k * x + b);
                ret = x;
            }
        };
        get(p[i][0]);
        if (k) {
            get(-b / k - 1);
            get(-b / k);
            get(-b / k + 1);
        }
        get(p[i + 1][0]);
    }
    cout << ret;
    
    return 0;
}

 

参考资料

  小白月赛113题解:https://ac.nowcoder.com/discuss/1480037

posted @ 2025-03-29 10:26  onlyblues  阅读(38)  评论(0)    收藏  举报
Web Analytics