题意
对于数字(1)~(2n),可以构造出(n)个二元组,对于(n)个二元组,选择一个数组(x),留下(x)个二元组的最小值,留下(n-x)个二元组的最大值,其构成了一个集合。
现在给定一个集合(b),问有多少种(x)的取值可以得到该集合。
分析
首先判定的是(x),所以对于任意(x)来说,前(x)个一定为留下的最小值,否则若(x<y),且(x)为取的最大值而(y)为取的最小值,那不妨交换(x)和(y)同样满足条件。那么我们只需要判定每一个(x)的取值是否合法。
假设当前取值为(i),那么对于前(i)个数,都可以找到一个比其大的数配对,而对于后(n-i)个数,都可以找到一个比其小的数配对。贪心的将丢弃的数放置在一个(set)中,对于前(i)个数,贪心的找到最小的比其大的数,若是无法找到,则表示该位置无法取值。同样对于后(n-i)个数,贪心的找到其最大的比其小的数,若是无法找到,则表示该位置无法取值。
我们可以发现一个性质,如果第(i)个位置是可行的,那么要保证前(i)个数是可以有配对数的,同时后(n-i)个数也是可以有配对数的,那么我们正着判断前(i)个数,反着判断后(n-i)个数,判断完后扫一遍即可。
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define ull unsigned long long
#define int ll
#define ls st<<1
#define rs st<<1|1
#define pii pair<int,int>
#define rep(z, x, y) for(int z=x;z<=y;++z)
#define repd(z, x, y) for(int z=x;z>=y;--z)
#define com bool operator<(const node &b)const
using namespace std;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
const int maxn = (ll) 1e6 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
int T = 1;
int a[maxn];
int n;
bool pre[maxn], last[maxn];
void solve() {
cin >> n;
set<int> s, t;
rep(i, 1, 2 * n)s.insert(i), t.insert(i);
rep(i, 1, n) {
pre[i] = last[i] = false;
int x;
cin >> x;
s.erase(x);
t.erase(x);
a[i] = x;
}
sort(a + 1, a + n + 1);
int ans = 0;
rep(i, 1, n) {
while (!s.empty() && *s.begin() < a[i])
s.erase(s.begin());
if (s.empty())
break;
if (*s.begin() > a[i])
s.erase(s.begin());
else
break;
pre[i] = true;
}
repd(i, n, 1) {
while (!t.empty() && *(--t.end()) > a[i])
t.erase(--t.end());
if (t.empty())
break;
if (*(--t.end()) < a[i])
t.erase(--t.end());
else
break;
last[i] = true;
}
pre[0] = last[n + 1] = true;
rep(i, 0, n)ans += (pre[i] && last[i + 1]);
cout << ans << '
';
}
signed main() {
start;
cin >> T;
while (T--)
solve();
return 0;
}