题目来源:
http://acm.zzuli.edu.cn/problem.php?id=2558
题目描述:
题意:
给定数字 和 ,分别代表 个数字和 次操作。每次操作都会使 个数字中的最大值减1最小值加1,在 次操作内,数组最大值与最小值的差值最小为多少。
思路:
PS:一眼看到,woc这不是
分的二分吗,然后仔细一看,原来是弱化版本呀,吓死我了还以为新生这么强
既然是对最值改变,那么我们只需要二分最小值和最大值,使得最小值最大化和最大值最小化,得到最大值,每次判断遍历
来
这个最大值是否可行。最小值同样如此。
参考代码:
/* CF was purple years ago!
* Thanks cf-tool!
* Author: nuoyanli
* Time: 2019-11-15 09:35:09
**/
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define lson l, mid, root << 1
#define rson mid + 1, r, root << 1 | 1
#define min(a, b) a > b ? b : a
#define max(a, b) a < b ? b : a
#define ll long long
using namespace std;
const int N = 1e4 + 10;
const int M = 25;
struct node {
ll x, y;
bool operator<(const node &_a) const { return y < _a.y; }
};
ll n, k, a[N], l, r, mid, ans_1, ans_2;
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while (t--) {
cin >> n >> k;
ll sum = 0;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
sum += a[i];
}
sort(a + 1, a + 1 + n);
l = 0, r = sum / n;
while (l < r) {
mid = (l + r + 1) >> 1;
ll temp = 0;
for (int i = 1; i <= n; ++i)
if (mid > a[i])
temp += mid - a[i];
if (temp <= k)
l = mid;
else
r = mid - 1;
}
ans_1 = l;
l = sum / n, r = a[n];
while (l < r) {
mid = (l + r) >> 1;
ll temp = 0;
for (int i = 1; i <= n; ++i)
if (mid < a[i])
temp += a[i] - mid;
if (temp <= k)
r = mid;
else
l = mid + 1;
}
ans_2 = l;
cout << ans_2 - ans_1 << endl;
}
return 0;
}