agc040B - Two Contests

题意:n(10^5)个问题,每个问题能被[li,ri]的人解决,要把n个问题分到两次测试中,使AK的人最多,测试至少包含一个问题。

找到最小的r(rmin)和最大的l(lmax),然后考虑两种情况,

1:rmin和lmax在一场测试中,显然此时答案为max(rmin-lmax,0)+除端点包含这两个点的线段中最长的一段

2.  rmin和lmax不在一场测试中,令x=max(ri-lmax+1,0),y=max(rmin-li,0),此时答案为min(x)+min(y),可以通过对x排序来维护y的前缀最小值O(n)实现

#include <bits/stdc++.h>

using namespace std;


int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i] >> b[i];
    }
    int min_b = *min_element(b.begin(), b.end());
    int max_a = *max_element(a.begin(), a.end());
    int ans = 0;
    vector<pair<int, int>> p(n);
    for (int i = 0; i < n; i++) {
        p[i] = make_pair(min_b - a[i] + 1, b[i] - max_a + 1);
    }
    sort(p.begin(), p.end());
    int m2 = (int)1.01e9;
    for (int i = 0; i < n - 1; i++) {
        m2 = min(m2, p[i].second);
        ans = max(ans, p[i + 1].first + m2);
    }
    for (int i = 0; i < n; i++) {
        int cur = b[i] - a[i] + 1;//此时包含两个端点的边在计算时一定小于等于最终答案,所以不用特别处理
        cur += max(0, min_b - max_a + 1);
        ans = max(ans, cur);
    }
    cout << ans << '\n';
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/noob1/p/11878989.html
two