• Codeforces 1463D Pairs


    题意

    对于数字(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;
    }
    
  • 相关阅读:
    利用 .NET Framework 命令行工具
    和AI机器人Alice的一段聊天记录
    WINDOWS自启动程序的10大隐身之所
    开放式开发/开源项目TimeDog[C#WindowsApp]
    Microsoft月度中文速递
    新安装的VS2003出现了一个问题不能新建项目!
    实例构造器和类型构造器的一些比较
    C++ 模板里面的typename
    vim 折叠的用法
    Redis3:持久化
  • 原文地址:https://www.cnblogs.com/F-Mu/p/14152997.html
Copyright © 2020-2023  润新知