Exam Results

题意

  给定两个长度为n的数组a和b,对于第i个人,你需要为他选取一个分数,要么是a[i],要么是b[i]。然后选完之后会根据n个人中的最高分生成一个及格线为max{sc[i]} * p%。

问你最多能使多少个人及格。

分析

 我可以把a数组和b数组进行合并,然后形成一个新数组,每个元素记录值和id,然后根据值的大小从小到大排序。然后进行尺取,每次维护一个n个人都有分数的区间,然后右边界c[r].val就是当前的最高分,

通过c[r].val * p%求得分数线,然后利用set维护一下,通过lower_bound可以找到第一个及格的人是谁。这样我们就可以求出最多有多少个人及格。

代码

 

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 7;
typedef long long ll;
int n; ll p;
ll a[MAXN], b[MAXN];
pair<ll, int> c[MAXN << 1];
struct BIT {
    int c[MAXN << 1];
    int lowbit(int x) {
        return x & (-x);
    }
    void add(int pos, int val) {
        for (int i = pos; i <= 2 * n; i += lowbit(i)) c[i] += val;
    }
    int ask(int pos) {
        int val = 0;
        for (int i = pos; i >= 1; i -= lowbit(i)) val += c[i];
        return val;
    }
    void clear() {
        for (int i = 1; i <= 2 * n; i++) c[i] = 0;
    }
}bit;
set<pair<ll, int>> st;
ll pre[MAXN]; int num[MAXN], ppos[MAXN];
void solve() {
    scanf("%d%lld", &n, &p);
    bit.clear();
    st.clear();
    for (int i = 1; i <= n; i++) pre[i] = num[i] = ppos[i] = 0;
    for (int i = 1; i <= n; i++) scanf("%lld%lld", &a[i], &b[i]);
    for (int i = 1; i <= n; i++) a[i] *= 100, b[i] *= 100;
    for (int i = 1; i <= n; i++) {
        c[i].first = a[i];
        c[i + n].first = b[i];
        c[i].second = c[i + n].second = i;
    }
    sort(c + 1, c + 1 + 2 * n);
    int cnt = 0, r = 1, first = 1;
    int ret = 0;
    for (int l = 1; l <= 2 * n; l++) {
        while (r <= 2 * n && cnt < n) {
            if (++num[c[r].second] == 1) {
                st.insert(c[r]);
                pre[c[r].second] = c[r].first;
                cnt++;
                bit.add(r, 1);
                ppos[c[r].second] = r;
            } else {
                auto pos = st.find(make_pair(pre[c[r].second], c[r].second));
                st.erase(pos);
                st.insert(c[r]);
                --num[c[r].second];
                bit.add(ppos[c[r].second], -1);
                ppos[c[r].second] = r;
                bit.add(r, 1);
            }
            if (!first) {
                ll sc = c[r].first / 100 * p;
                auto pos = st.lower_bound(make_pair(sc, 0));
                int lpos = ppos[pos->second];
                int temp = bit.ask(r) - bit.ask(lpos - 1);
                ret = max(ret, temp);
            }
            r++;
        }
        first = 0;
        ll sc = c[r - 1].first / 100 * p;
        auto pos = st.lower_bound(make_pair(sc, 0));
        int lpos = ppos[pos->second]; // 看这个数上一次出现的位置
        int temp = bit.ask(r - 1) - bit.ask(lpos - 1);
        ret = max(ret, temp);
        pos = st.find(c[l]);
        if (pos != st.end()) {
            st.erase(pos);
            bit.add(l, -1);
        }
        if (!--num[c[l].second]) cnt--;
    }
    printf("%d\n", ret);
}
int main() {
    int T;
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        cout << "Case #" << cas << ": ";
        solve();
    }
    return 0;
}

 

posted @ 2020-10-19 14:22  HighLights  阅读(541)  评论(0)    收藏  举报