题意node
对于数字\(1\)~\(2n\),能够构造出\(n\)个二元组,对于\(n\)个二元组,选择一个数组\(x\),留下\(x\)个二元组的最小值,留下\(n-x\)个二元组的最大值,其构成了一个集合。ios
如今给定一个集合\(b\),问有多少种\(x\)的取值能够获得该集合。c++
分析数组
首先断定的是\(x\),因此对于任意\(x\)来讲,前\(x\)个必定为留下的最小值,不然若\(x<y\),且\(x\)为取的最大值而\(y\)为取的最小值,那不妨交换\(x\)和\(y\)一样知足条件。那么咱们只须要断定每个\(x\)的取值是否合法。spa
假设当前取值为\(i\),那么对于前\(i\)个数,均可以找到一个比其大的数配对,而对于后\(n-i\)个数,均可以找到一个比其小的数配对。贪心的将丢弃的数放置在一个\(set\)中,对于前\(i\)个数,贪心的找到最小的比其大的数,如果没法找到,则表示该位置没法取值。一样对于后\(n-i\)个数,贪心的找到其最大的比其小的数,如果没法找到,则表示该位置没法取值。code
咱们能够发现一个性质,若是第\(i\)个位置是可行的,那么要保证前\(i\)个数是能够有配对数的,同时后\(n-i\)个数也是能够有配对数的,那么咱们正着判断前\(i\)个数,反着判断后\(n-i\)个数,判断完后扫一遍便可。ci
#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 << '\n'; } signed main() { start; cin >> T; while (T--) solve(); return 0; }