最快相同

最快相同

题目描述

现在有一个由 $n$ 个整数组成的数组 ${a_1,a_2,\ldots,a_n}$,你可以进行以下操作任意次(可以是 $0$ 次):

  • 每次操作恰好选择 $k$ 个不同的位置,并使这些位置上的元素值减一;形式地说,每次操作可以选择一个大小为 $k$ 的集合 $S={p_1,p_2,\ldots,p_k}$,对于集合中的每个元素都使得 $a_{p_i} \to a_{p_i}−1$。

现在,你想要将整个数组的元素都变为相同值,求解最少需要的操作次数。特别地,如果无论怎样操作都无法使得数组所有元素都变为相同值,则直接输出 $−1$。

输入描述:

第一行输入两个整数 $n,k \left(1\le k \le n \le 10^5 \right)$ 代表数组中的元素个数、单次操作的位置数。

第二行输入 $n$ 个整数 $a_1, a_2, \dots, a_n \left(1\le a_i \le 10^9 \right)$ 代表数组中的元素。

输出描述:

如果不存在一种操作方案,使得数组所有元素变为相同值,输出 $−1$。否则,输出一个整数,代表最少操作次数。

示例1

输入

3 2
1 1 2

输出

2

说明

在这个样例中,每一次的操作如下:

第一次操作选择位置 $2$ 和 $3$,数组变为 ${1,0,1}$;

第二次操作选择位置 $1$ 和 $3$,数组变为 ${0,0,0}$。

我们可以证明,这是最少需要的操作次数。

示例2

输入

4 4
1 1 1 2

输出

-1

 

解题思路

  假设操作了 $x$ 次最后使得所有的数都变成 $y$,记 $s = \sum\limits_{i=1}^{n}{a_i}$,那么有 $s - kx = ny \Rightarrow kx + ny = s$。由裴蜀定理知道,只有当 $\gcd(k, n) \mid s$ 时,才有整数解 $x$ 和 $y$。因此如果 $\gcd(k, n) \nmid s$ 时,则无解。另外还需要特判 $n=k$ 的情况,此时只有所有数都相同时才有解(最小操作次数为 $0$),否则无解。

  为了求出一个可行的 $x$ 和 $y$,我们先通过扩展欧几里得算法求出线性同余方程 $kx' + ny' = \gcd(k, n)$ 的一个可行解 $x'$ 和 $y'$,然后令 $x \gets x' \cdot \frac{s}{d}$,$y \gets y' \cdot \frac{s}{d}$,此时就有 $kx + ny = s$。当然这里的 $x$ 和 $y$ 只是一个可行解,实际上有通解 $\displaylines{\begin{cases} X = x + \frac{n}{d}c \\ Y = y - \frac{k}{d}c \end{cases}}$,其中 $c \in \mathbb{Z}$。

  显然并不是所有的 $X$ 和 $Y$ 能满足条件。实际上我们除了保证 $\gcd(k, n) \mid s$ 时有解外,还需要满足最终每个数 $Y$ 不超过原始数组 $a$ 的最小值,即 $Y \leq \min\{a_i\}$,以及操作次数 $X$ 不少于原始数组 $a$ 的最大值变成 $Y$ 的操作次数,即 $X \geq \max\{a_i\} - Y$(一开始没考虑这个条件 WA 了一下午......)。所以有

$$\begin{cases}
y - \frac{k}{d}c \leq \min\{a_i\} \\
x + \frac{n}{d}c \geq \max\{a_i\} - \left( y - \frac{k}{d}c \right)
\end{cases}
\Rightarrow 
\begin{cases}
c \geq \left\lceil \frac{y - \min\{a_i\}}{k/d} \right\rceil\\
c \geq \left\lceil \frac{\max\{a_i\}-x-y}{(n-k)/d} \right\rceil\\
\end{cases}$$

  因此当 $c = \max\left\{ \left\lceil \frac{y - \min\{a_i\}}{k/d} \right\rceil, \, \left\lceil \frac{\max\{a_i\}-x-y}{(n-k)/d} \right\rceil \right\}$,操作次数 $X$ 能取最小值 $x + \frac{n}{d}c$。

  AC 代码如下,时间复杂度为 $O(n)$:

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

typedef long long LL;

const int N = 1e5 + 5;

int a[N];

int exgcd(int a, int b, LL &x, LL &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

LL ceil(LL x, LL k) {
    if (x >= 0) return (x + k - 1) / k;
    return x / k;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    LL s = 0;
    int mn = 1e9, mx = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        s += a[i];
        mn = min(mn, a[i]);
        mx = max(mx, a[i]);
    }
    if (n == m) {
        cout << (mn == mx ? 0 : -1);
        return 0;
    }
    LL x, y;
    int d = exgcd(m, n, x, y);
    if (s % d) {
        cout << -1;
        return 0;
    }
    x *= s / d;
    y *= s / d;
    cout << x + n / d * max(ceil(y - mn, m / d), ceil(mx - x - y, (n - m) / d));
    
    return 0;
}

 

参考资料

  牛客小白月赛111 官方题解:https://ac.nowcoder.com/discuss/1464410

posted @ 2025-03-08 19:55  onlyblues  阅读(57)  评论(0)    收藏  举报
Web Analytics