题目来源:
https://codeforces.com/problemset/problem/1244/E
題目描述:
题意:
给定一个长度为 的序列和一个操作次数 ,现在你可以给任意一个数加一或者减一,问不超过 次能取得的最小极差是多少。
思路:
因为是问的极差,所以肯定是对当前的最大值和最小值进行改变最优,所以问题具有单调性,二分极值是否满足 次即可,预处理前缀和。
参考代码:
/* 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 = 1e5 + 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], sum[N];
bool check(int x) {
ll ans = 1e18, r = 1, l = 1;
for (int i = 1; i <= n; i++) {
while (r < n && a[r + 1] - a[i] <= x)
r++;
ans = min(ans, a[i] * i - sum[i] + sum[n] - sum[r] - (a[i] + x) * (n - r));
}
for (int i = 1; i <= n; i++) {
while (a[i] - a[l] > x)
l++;
ans = min(ans, sum[n] - sum[i] - a[i] * (n - i) + (a[i] - x) * (l - 1) - sum[l - 1]);
}
return ans <= k;
}
signed main() {
// printf("%lld\n", inf);
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i];
int l = 0, r = a[n] - a[1] + 1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid))
r = mid - 1;
else
l = mid + 1;
}
return !printf("%d\n", l);
return 0;
}