zoukankan      html  css  js  c++  java
  • Codeforces Round #672 (Div. 2)

    比赛链接:https://codeforces.com/contest/1420

    A. Cubes Sorting

    题意

    给出一个大小为 $n$ 的数组 $a$,每次只可以交换相邻的两个元素,最多交换 $frac{n cdot (n-1)}{2}-1$ 次,判断能否将数组变为非递减序。

    题解一

    交换次数最多为 $frac{n cdot (n-1)}{2}$,此时数组为严格递减序,即 $a_1 > a_2 > dots > a_{n - 1} > a_n$,从小到大每个元素依次需要交换 $n-1,n-2,dots,1,0$ 次,除此外总的交换次数一定会小于 $frac{n cdot (n-1)}{2}$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            vector<int> a(n);
            for (int i = 0; i < n; i++)
                cin >> a[i];
            if (is_sorted(a.begin(), a.end(), greater<int>()) and unique(a.begin(), a.end()) == a.end())
                cout << "NO" << "
    ";
            else
                cout << "YES" << "
    ";
        }
        return 0;
    }

    题解二

    利用单调递减栈计算之前有多少个元素大于当前元素,即为当前元素需要交换的次数。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            int cnt = 0;
            stack<int> stk;
            for (int i = 0; i < n; i++) {
                int x;
                cin >> x;
                while (stk.size() and stk.top() <= x) stk.pop();
                cnt += stk.size();
                stk.push(x);
            }
            cout << (cnt <= 1LL * n * (n - 1) / 2 - 1 ? "YES" : "NO") << "
    ";
        }
        return 0;
    }

    B. Rock and Lever

    题意

    给出一个大小为 $n$ 的数组 $a$,计算满足:

    • $i < j$
    • $a_i   &   a_j ge a_i oplus a_j$

    的二元组 $(i,j)$ 的数目。

    题解

    只有当 $a_i$ 与 $a_j$ 二进制下的最高位相同时才满足条件,记录每一最高位的元素个数,答案即 $sum_{i=0}^{31}C_i^2$ 。

    代码

    #include <bits/stdc++.h>
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            long long ans = 0;
            int cnt[32] = {};
            for (int i = 0; i < n; i++) {
                int x;
                cin >> x;
                ans += cnt[__lg(x)]++;
            }
            cout << ans << "
    ";
        }
        return 0;
    }

    C2. Pokémon Army (hard version)

    题意

    给出一个大小为 $n$ 的数组 $a$,计算 $a$ 的最大子序列交错和,之后交换 $q$ 对元素,计算每次交换后的最大子序列交错和。

    题解

    以下标为横坐标,值为纵坐标,最大序列交错和即为 峰顶 - 谷底 + 峰顶 - 谷底 ……

    每次交换只会改变两个交换元素及相邻元素是否为峰底的情况,对这最多 $6$ 个元素重新计算即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) {
            int n, q;
            cin >> n >> q;
            vector<int> a(n + 2);
            for (int i = 1; i <= n; i++)
                cin >> a[i];
            long long ans = 0;
            auto add = [&](int x, int c) {
                if (x == 0 or x == n + 1)
                    return;
                if (a[x - 1] <= a[x] and a[x] >= a[x + 1])
                    ans += a[x] * c;
                if (a[x - 1] >= a[x] and a[x] <= a[x + 1])
                    ans -= a[x] * c;
            };
            for (int i = 1; i <= n; i++)
                add(i, 1);
            cout << ans << "
    ";
            while (q--) {
                int l, r;
                cin >> l >> r;
                for (int i = -1; i <= 1; i++) {
                    add(l + i, -1);
                    if (r + i > l + 1)
                        add(r + i, -1);
                }
                swap(a[l], a[r]);
                for (int i = -1; i <= 1; i++) {
                    add(l + i, 1);
                    if (r + i > l + 1)
                        add(r + i, 1);
                }
                cout << ans << "
    ";
            }
        }
        return 0;
    }

    D. Rescue Nibel!

    题意

    给出 $n$ 盏灯的亮灯区间,计算有多少种选择使得同一时刻至少有 $k$ 盏灯是亮着的。

    题解

    将区间按照左端点从小到大排序,每次记录之前访问区间的右端点,利用优先队列或集合删除小于当前区间的左端点的右端点,此时余下的右端点的个数即为可以与当前灯在同一时刻亮着的灯的个数,选择个数为 $C_i^{k-1}$ 。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    constexpr int N = 1e6 + 100;
    constexpr int MOD = 998244353;
    
    int fac[N], inv[N];
    
    int binpow(int a, int b) {
        int res = 1;
        while (b) {
            if (b & 1) res = 1LL * res * a % MOD;
            a = 1LL * a * a % MOD;
            b >>= 1;
        }
        return res;
    }
    
    int C(int n, int m){
        if(m < 0 or m > n) return 0;
        return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    void Init(){
        fac[0] = 1;
        for (int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MOD;
        inv[N - 1] = binpow(fac[N - 1], MOD - 2);
        for (int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        Init();
    
        int n, k;
        cin >> n >> k;
    
        vector<pair<int, int>> a(n);
        for (int i = 0; i < n; i++)
            cin >> a[i].first >> a[i].second;
    
        sort(a.begin(), a.end());
    
        long long ans = 0;
    
        priority_queue<int, vector<int>, greater<int>> pque;
    
        for (int i = 0; i < n; i++) {
            while (pque.size() and pque.top() < a[i].first) pque.pop();
            (ans += C(pque.size(), k - 1)) %= MOD;
            pque.push(a[i].second);
        }
    
        cout << ans << "
    ";
    
        return 0;
    }
  • 相关阅读:
    SAMBA服务初学练习
    NFS与AutoNFS实例
    NTP服务简介
    DHCP服务简单搭建步骤
    HBase文档操作--练习篇
    Hadoop体系结构管理
    HBase表结构设计--练习篇
    HBase备份恢复练习
    MongoDB管理练习
    24_BlockingQueue接口
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13728529.html
Copyright © 2011-2022 走看看