最快相同
最快相同
题目描述
现在有一个由 $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
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18759768