As we all know, Honk has nn pools, numbered as 11 ~ nn . There is a_iai liters water in the ii-th pool. Every day, Honk will perform the following operations in sequence.
我们都知道,浩克有n个池子,以1~n标号,在第i个池子里有ai升水,每一天,浩克都会依序重复下列操作:
-
Find the pool with the most water (If there are more than one, choose one at random) and take one liter of water.(找到水最多的一个池子(如果有多个水最多的池子,任意选择一个),从中取一升水)
-
Find the pool with the least water (If there are more than one, choose one at random) and pour one liter of water into the pool.(找到水最少的一个池子(如果有多个水最少的池子,任意选择一个),把那一升水倒入其中)
-
Go home and rest (Waiting for the next day).(回家睡觉等待下一天)
Please calculate the difference between the amount of water in the pool with the most water and the amount of water in the pool with the least water after the kk days.
请计算出k天后的泳池水量的极差。
首先求出全体水量的平均值,这个平均值意味着最小值的向上最大范围和最大值的向下最小范围。如果平均值不能整除,则令最大值的向下最小范围加一即可。
在n个池子中,转移量是一定的,也就是开头给出的k,而要求这些转移量可以对高于平均值和低于平均值的池子的极值造成什么样的影响,就可以用二分求出。具体操作就是二分到某个值a时,就遍历数组,用比它大的值减去a(如果求最小值的上界,那就去用a减数组元素),就可以得到把最大值降到a所需的转移量,最后与k比较即可
- 比如样例 4 100 1 1 10 10
- 可以看出所有水池的最终状态是5 5 6 6
- 最大最小值都改变的第一个状态是2 2 9 9,所需转移量为2,k满足这个大小
- 最大最小值都改变的第二个状态是3 3 8 8,所需转移量为4,k满足这个大小
- …………
- 最终状态是5 5 6 6,所需转移量是8,k满足此大小
如上过程所述,如果在中间出现不满足的情况直接跳出,在二分里依据情况重新划分区间查询即可。这些转移量都是使得水池的最大最小值足以发生改变的数值,不会出现使得水池水量为2 1 9 10这样情况的转移量。
值得一说的是,对枚举范围进行确定可以对时间效率上进行优化,比如说最大值的上下界是【平均值,数组最大值】,最小值的上下界时【数组最小值,平均值】
#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#pragma GCC optimize(2)
#pragma warning(disable:4996)
#define lldin(a) scanf("%lld", &a)
#define println(a) printf("%lld\n", a)
#define print(a) printf("%lld ", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
#define BigInteger __int128
const int INF = 2e9 + 2;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1e9 + 7;
//template<typename T>
//inline BigInteger nextBigInteger()
//{
// BigInteger tmp = 0, si = 1;char c; c = getchar();
// while (!isdigit(c))
//{if (c == '-')si = -1;c = getchar();}
// while (isdigit(c))
// {tmp = tmp * 10 + c - '0';c = getchar();}
// return si * tmp;
//}
//std::ostream& operator<<(std::ostream& os, __int128 T)
//{
// if (T<0) os<<"-";if (T>=10 ) os<<T/10;if (T<=-10) os<<(-(T/10));
// return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//void output(BigInteger x)
//{
// if (x < 0)
// {x = -x;putchar('-');}
// if (x > 9) output(x / 10);
// putchar(x % 10 + '0');
// }
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
ll arr[234234];
bool check(ll curstatus, ll reality, ll limit, bool sign = false)
{
ll tmpcost = 0;
for (int i = 1; i <= limit; i++)
{
if (arr[i] >= curstatus && sign == false)
tmpcost += arr[i] - curstatus;
else if (arr[i] <= curstatus && sign == true)
tmpcost += curstatus - arr[i];
}
if (tmpcost > reality)
return false;
else
return true;
}
int DETERMINATION()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0), std::cout.tie(0);
ll n, k;
while (std::cin >> n >> k)
{
ll sum = 0, mn = INF, mx = 0;
for (int i = 1; i <= n; i++)
{
std::cin >> arr[i];
sum += arr[i];
mx = std::max(arr[i], mx);
mn = std::min(arr[i], mn);
}
ll lower = 0, upper = 0;
if (sum%n == 0)
{
lower = sum / n;
upper = sum / n;
}
else
{
lower = sum / n + 1;
upper = sum / n;
}
//std::cout << lower << "%$^" << upper << std::endl;
ll finlower = 0, finupper = 0;
ll tmplower = lower, tmpupper = mx;
while (tmplower <= tmpupper)
{
ll mid = (tmplower + tmpupper) >> 1;
if (check(mid, k, n, false))
{
tmpupper = mid - 1;
finupper = mid;
}
else
tmplower = mid + 1;
}
//std::cout << finupper << std::endl;
tmplower = 0;
tmpupper = upper;
while (tmplower <= tmpupper)
{
ll mid = (tmplower + tmpupper) >> 1;
if (check(mid, k, n, true))
{
finlower = mid;
tmplower = mid + 1;
}
else
tmpupper = mid - 1;
}
//std::cout << finupper << " " << finlower << std::endl;
std::cout << finupper - finlower << std::endl;
}
return 0;
}