D. Salary Changing(二分,前綴和,貪心,瞎搞)

Salary Changing

Thinking

這道題第一思路就是二分,模擬了一下樣例,感覺好像行於是就開始寫。

對於二分,我們一定是二分中位數是什麼,二分的邊界對我們來說是非常重要的,所以我們在二分前有必要確認我們的二分邊界,因爲一定有i=1nli<=s\sum _{i = 1} ^ {n} l_i <= s,所以我們對ll數組sortsort一遍,得到left=lmidleft = l_{mid},同樣的,對rr數組sortsort一遍,得到right=rmidright = r_{mid},接下來我們就可以開始我們的二分了。

但是這道題的難點不是在二分思想上,而是judgejudge函數有點難寫:

  • 首先我們對每一個人的salarysalary按照rr從小到大排序。
  • 接下來,我們可以通過二分得到salaryl<=mid<=salaryrsalary_l <= mid <= salary_r的人數量numnum,如果n<n/2+1n < n / 2 + 1這個二分值過大,直接返回false。
  • 否則我們進行貪心的選值,記錄下這些點的salarylsalary_l,然後進行排序,優先選擇小的去補充我們所需的salary<midsalary < mid,但是還沒有選滿的。
  • 接下來就是對於salary>=midsalary >= mid的進行貪心選,假設他的salaryl>xsalary_l > x就選擇salarylsalary_l,否則的話就是選擇xx

下面代碼中有更詳細的描述judgejudge函數。

Coding

#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;

inline ll read() {
    ll f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-')    f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return f * x;
}

const int N = 2e5 + 10;

ll L[N], R[N], n, s, m;

struct Node {
    int l, r;
    bool operator < (const Node & t) const {
        return r < t.r;
    }
}a[N];

bool judge(int x) {
    int p = lower_bound(R + 1, R + 1 + n, x) - R;
    int last = n - p + 1;//後面剩下了多少個數,
    if(last < m)    return false;//如果沒辦法滿足 >= x的人數至少有n / 2 + 1個,那麼x過大。
    vector<int> v;
    for(int i = p; i <= n; i++) v.pb(a[i].l);
    sort(v.begin(), v.end());
    int need = m - 1 - (p - 1);//前面選擇完任然不夠,所需要的。
    ll sum = L[p - 1];//一個前綴和數組,看main函數即可理解
    for(int i = 0; i < need; i++) {
        sum += v[i];
        if(v[i] > x)    return false;//一定滿足前面的數 <= x,
    }
    for(int i = need; i < v.size(); i++)    sum += max(x, v[i]);
    return sum <= s;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "r", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int _ = read();
    while(_--) {
        n = read(), s = read();
        m = n / 2 + 1;
        for(int i = 1; i <= n; i++) {
            a[i].l = read(), a[i].r = read();
            L[i] = a[i].l, R[i] = a[i].r;
        }
        sort(a + 1, a + 1 + n);
        sort(L + 1, L + 1 + n);
        sort(R + 1, R + 1 + n);
        int l = L[(n >> 1) + 1], r = R[(n >> 1) + 1];
        for(int i = 1; i <= n; i++)
            L[i] = a[i].l + L[i - 1];
        while(l < r) {
            int mid = l + r + 1 >> 1;
            if(judge(mid))  l = mid;
            else r = mid - 1;
        }
        printf("%d\n", l);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章