2019ICPC沈阳网络赛 F. Honk‘s pool

链接

https://nanti.jisuanke.com/t/41406

题意

有 $n$ 个水池,每天从水最多的水池取出一升水放入水最少的水池。

问 $k$ 天后水最多的水池和水最少的水池的差。

思路

可以发现所有水池的水量都趋于平均值移动。

因此只要二分确定最大值和最小值即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const int N=5e5+5;
int n,k,a[N];
bool check1(int mid) {
LL ret=0;
for(int i=n;a[i]>mid;i--) ret+=a[i]-mid;
return ret<=k;
}
bool check2(int mid) {
LL ret=0;
for(int i=1;a[i]<mid;i++) ret+=mid-a[i];
return ret<=k;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
while(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);
int ll,rr;
if(sum%n==0) ll=rr=sum/n;
else ll=sum/n,rr=ll+1;
int l=rr,r=a[n];
while(l<r) {
int mid=l+r>>1;
if(check1(mid)) r=mid;
else l=mid+1;
}
int res=l;
l=a[1],r=ll;
while(l<r) {
int mid=l+r+1>>1;
if(check2(mid)) l=mid;
else r=mid-1;
}
cout<<res-l<<'\n';
}
return 0;
}