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; }

浙公网安备 33010602011771号