Codeforces 1463D Pairs
阅读原文时间:2023年09月03日阅读:1

题意

对于数字\(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 << '\n';
}

signed main() {
    start;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器