BZOJ 4391: [Usaco2015 dec]High Card Low Card

预处理一下前缀后缀最大值
每次用set贪心取一个合适的数
然后枚举分割点
有可能两次都取了同一个数 \(x\),而 \(y\) 没被取到
\(x>y\),那么就可以在点数小的那一轮拿 \(y\) 替换 \(x\)
\(x<y\),那么就可以在点数大的那一轮拿 \(y\) 替换 \(x\)

#include <bits/stdc++.h>

inline int _i() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - 48LL, ch = getchar();
    return x * f;
}

const int N = 1e5 + 7;
int a[N], pre[N], suf[N];
bool vis[N];
std::set<int> st;

int main() {
    int n = _i();
    for (int i = 1; i <= n; i++)
        vis[a[i] = _i()] = 1;
    for (int i = 1; i <= 2 * n; i++)
        if (!vis[i]) st.insert(i);
    std::set<int>::iterator it;
    for (int i = 1; i <= n; i++) {
        it = st.lower_bound(a[i]);
        pre[i] = pre[i - 1];
        if (it != st.end()) st.erase(it), pre[i]++;
    }
    st.clear();
    for (int i = 1; i <= 2 * n; i++)
        if (!vis[i]) st.insert(i);
    for (int i = n; i; i--) {
        it = st.lower_bound(a[i]);
        suf[i] = suf[i + 1];
        if (it != st.begin()) --it, st.erase(it), suf[i]++;
    }
    int ans = 0;
    for (int i = 0; i <= n; i++)
        ans = std::max(ans, pre[i] + suf[i + 1]);
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/12324811.html