[AGC040B]Two Contests

Description

給出若干條線段 \((L[i], R[i])\) ,把他們分紅兩個非空的集合,最大化集合內線段交的和。ios

\(n\le 10 ^ 5\)git

Solution

考慮最小的一個右端點 p 和最大的一個左端點 q 。spa

討論:code

  1. p 和 q 在同一集合內,那麼選擇一條除了這兩條外最長的線段單獨一個集合,剩下的和 p, q 一塊兒一個集合。
  2. p 和 q 不在同一集合內,那麼考慮令 \(a_i = max(p - l_i+1, 0), b_i = max(r_i - q + 1, 0)\) , 問題就轉換成了把 {1,2...n} 劃分紅兩個集合 \(S, T\) ,而且最大化 \(min\{a_i\} + min\{b_j\}\), \(i\in S, j \in T\),能夠把 \((a_i, b_i)\)\(a_i\) 從大到小排序,而後 \(T\) 選的就是一段後綴。

code

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

#define End exit(0)
#define LL long long
#define mp make_pair
#define SZ(x) ((int) x.size())
#define GO cerr << "GO" << endl
#define DE(x) cout << #x << " = " << x << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)

void proc_status()
{
    freopen("/proc/self/status","r",stdin);
    string s; while(getline(cin, s)) if (s[2] == 'P') { cerr << s << endl; return; }
}

template<typename T> inline T read() 
{
    register T x = 0;
    register char c; register int f(1);
    while (!isdigit(c = getchar())) if (c == '-') f = -1;
    while (x = (x << 1) + (x << 3) + (c ^ 48), isdigit(c = getchar()));
    return x * f;
}

template<typename T> inline bool chkmin(T &a,T b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a,T b) { return a < b ? a = b, 1 : 0; }

const int maxN = 1e5 + 2;

struct Info
{
    int a, b;
    bool operator > (const Info& B) const { 
        return a > B.a;
    }
} info[maxN + 2];

int n, N;
int L[maxN + 2], R[maxN + 2];

void input()
{
    n = read<int>();
    for (int i = 1; i <= n; ++i) 
        L[i] = read<int>(), R[i] = read<int>();
}

int solve()
{
    int p = 1e9, q = 0;
    for (int i = 1; i <= n; ++i) chkmin(p, R[i]);
    for (int i = 1; i <= n; ++i) chkmax(q, L[i]);

    for (int i = 1; i <= n; ++i) info[i].a = max(p - L[i] + 1, 0);
    for (int i = 1; i <= n; ++i) info[i].b = max(R[i] - q + 1, 0);

    sort(info + 1, info + 1 + n, greater<Info>());

    static int suf[maxN + 2];

    suf[n + 1] = 1e9;
    for (int i = n; i >= 1; --i) suf[i] = min(suf[i + 1], info[i].b);

    int ans = 0;
    for (int i = 1; i <= n; ++i) chkmax(ans, max(p - q + 1, 0) + R[i] - L[i] + 1);
    for (int i = 1; i < n; ++i) chkmax(ans, suf[i + 1] + info[i].a);

    return ans;
}

int main() 
{
#ifndef ONLINE_JUDGE
    freopen("xhc.in", "r", stdin);
    freopen("xhc.out", "w", stdout);
#endif
    input();
    printf("%d\n", solve());
    return 0;
}
相關文章
相關標籤/搜索