预处理一下前缀后缀最大值
每次用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;
}
BZOJ 4391: [Usaco2015 dec]High Card Low Card
原文:https://www.cnblogs.com/Mrzdtz220/p/12324811.html