牛牛的揠苗助长(二分)

牛牛的揠苗助长

题目链接

思路

我们考虑最小值的时候通常会考虑二分,但是这道题题目该如何二分呢。

我们知道在时间为(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;
}
原文地址:https://www.cnblogs.com/lifehappy/p/12856076.html