郑轻 19级新生周赛(3)-张宇专场 数字差值(二分)

题目来源:

http://acm.zzuli.edu.cn/problem.php?id=2558

题目描述:

在这里插入图片描述

题意:

给定数字 n n k k ,分别代表 n n 个数字和 k k 次操作。每次操作都会使 n n 个数字中的最大值减1最小值加1,在 k k 次操作内,数组最大值与最小值的差值最小为多少。

思路:

PS:一眼看到,woc这不是 c f 2000 cf 2000 分的二分吗,然后仔细一看,原来是弱化版本呀,吓死我了还以为新生这么强
既然是对最值改变,那么我们只需要二分最小值和最大值,使得最小值最大化和最大值最小化,得到最大值,每次判断遍历 O ( n ) O(n) c h e c k check 这个最大值是否可行。最小值同样如此。

参考代码:

/* 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;
}
发布了293 篇原创文章 · 获赞 212 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/nuoyanli/article/details/103084370
今日推荐