題意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; }