牛牛的揠苗助长(二分)
牛牛的揠苗助长
思路
我们考虑最小值的时候通常会考虑二分,但是这道题题目该如何二分呢。
我们知道在时间为(t)的范围内我们能改变数组中(2t)个值,所以这道题目就是以时间为边界去二分,每当我们经过(t)个时间,显然数组中的某一些项会增加。这个时候对数组排一个序,中间的值将会是最优的,也就是(t)时间时,需要人为去变换值的基准,然后以这个为基准进行一趟变换,求得人为需要调动的次数,再跟(t)进行比较,如果(调动次数 <= t)这个时候说明可能存在更优解,更新二分边界(r = mid)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N], b[N];
int n;
bool judge(ll mid) {
for(int i = 1; i <= n; i++) {
b[i] = a[i] + mid / n;
if(mid % n >= i) b[i]++;
}
sort(b + 1, b + 1 + n);
ll ans = b[n + 1 >> 1], sum = 0;
for(int i = 1; i <= n; i++)
sum += llabs(b[i] - ans);
return sum <= mid;
}
int main() {
// freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
ll l = 1, r = 1e18;
while(l < r) {
ll mid = l + r >> 1;
if(judge(mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
return 0;
}